Example #1
0
 def delete_final_gdb(finalgdb):
     """Deletes final geodatabase"""
     if gp.Exists(finalgdb) and cfg.STEP5:
         try:
             lu.clean_out_workspace(finalgdb)
         except:
             lu.dashline(1)
             msg = ('ERROR: Could not remove contents of geodatabase ' +
                    finalgdb + '. \nIs it open in ArcMap? You may '
                    'need to re-start ArcMap to release the file lock.')
             lu.raise_error(msg)
         lu.delete_dir(finalgdb)
Example #2
0
 def delete_final_gdb(finalgdb):
     """Deletes final geodatabase"""
     if gp.Exists(finalgdb) and cfg.STEP5:
         try:
             lu.clean_out_workspace(finalgdb)
         except:
             lu.dashline(1)
             msg = ('ERROR: Could not remove contents of geodatabase ' +
                    finalgdb + '. \nIs it open in ArcMap? You may '
                    'need to re-start ArcMap to release the file lock.')
             lu.raise_error(msg)
         lu.delete_dir(finalgdb)
Example #3
0
def circuitscape_master(argv=None):
    """

    """
    gprint = lu.gprint
    gwarn = arcpy.AddWarning

    if argv is None:
        argv = sys.argv    
    
    cfg.configure(cfg.TOOL_CS, argv)
    gp = cfg.gp

    
    try:
        lu.create_dir(cfg.LOGDIR)
        lu.create_dir(cfg.MESSAGEDIR)
        cfg.logFilePath=lu.create_log_file(cfg.MESSAGEDIR, cfg.TOOL, 
                                           cfg.PARAMS) 

        CSPATH = lu.get_cs_path()
        if CSPATH == None:
            msg = ('Cannot find an installation of Circuitscape 3.5.5'
                    '\nor greater in your Program Files directory.')
            arcpy.AddError(msg)
            lu.write_log(msg)
            exit(1)
            
        try:
            csDir, fn = path.split(CSPATH)
            if 'flush' not in open(path.join(csDir,'cs_compute.py')).read():
                gwarn('\n---------------------------------------------')
                gwarn('Your version of Circuitscape is out of date. ')
                gwarn('---------------------------------------------\n')
                gwarn('Please get the latest from www.circuitscape.org.')
                gwarn('The new version interacts more smoothly with ArcMap.')
                gprint('Proceeding...\n')
        except: pass
        
        lu.print_drive_warning()
        # Check core ID field.
        lu.check_cores(cfg.COREFC, cfg.COREFN)

        gp.OutputCoordinateSystem = gp.describe(cfg.COREFC).SpatialReference
        # Set data frame spatial reference to coordinate system of input data 
        lu.set_dataframe_sr()
        
        gp.pyramid = "NONE"
        gp.rasterstatistics = "NONE"

        # Move adj and cwd results from earlier versions to datapass directory
        lu.move_old_results()
    
        if cfg.CWDCUTOFF > 0:
            lu.delete_dir(cfg.SCRATCHDIR)

        # restart code- in progress
        if cfg.CWDCUTOFF < 0:
            cfg.CWDCUTOFF = cfg.CWDCUTOFF * -1
            
        if not cfg.DOPINCH and not cfg.DOCENTRALITY:
            msg = ('ERROR: Please choose at least one option: pinch point or\n'
                    'network centrality analysis.')
            lu.raise_error(msg)

        lu.create_dir(cfg.SCRATCHDIR)
        lu.create_dir(cfg.ARCSCRATCHDIR)

        if cfg.DO_ALLPAIRS:
            #  Fixme: move raster path to config
            S5CORRIDORRAS = path.join(cfg.OUTPUTGDB,cfg.PREFIX + "_corridors")
            if not gp.Exists(S5CORRIDORRAS):
                S5CORRIDORRAS = path.join(cfg.OUTPUTGDB, cfg.PREFIX +
                                         "_lcc_mosaic_int")
            if not gp.Exists(S5CORRIDORRAS):
                msg = ('ERROR: Corridor raster created in step 5 is required'
                        '\nfor all-pair analyses, but was not found.')
                lu.raise_error(msg)
        if cfg.DOPINCH:
            if cfg.CWDCUTOFF == '#' or cfg.CWDCUTOFF == 0:
                msg = ('ERROR: CWD cutoff distance is required for pinch point'
                        ' analyses.')
                lu.raise_error(msg)
            
            # Make a local grid copy of resistance raster-
            # will run faster than gdb.
            lu.delete_data(cfg.RESRAST)
            if not gp.Exists(cfg.RESRAST_IN):
                msg = ('ERROR: Resistance raster is required for pinch point'
                        ' analyses, but was not found.')
                lu.raise_error(msg)
            
            desc = arcpy.Describe(cfg.RESRAST_IN)
            if hasattr(desc, "catalogPath"):
                cfg.RESRAST_IN = arcpy.Describe(cfg.RESRAST_IN).catalogPath
            
            arcpy.env.extent = cfg.RESRAST_IN
            arcpy.env.snapRaster = cfg.RESRAST_IN
            gprint('\nMaking local copy of resistance raster.')
            gp.CopyRaster_management(cfg.RESRAST_IN, cfg.RESRAST)

        if cfg.DOCENTRALITY:
            gprint("Creating output folder: " + cfg.CENTRALITYBASEDIR)
            if path.exists(cfg.CENTRALITYBASEDIR):
                shutil.rmtree(cfg.CENTRALITYBASEDIR)
            lu.create_dir(cfg.CENTRALITYBASEDIR)
            gp.CreateFolder_management(cfg.CENTRALITYBASEDIR,
                                        cfg.CIRCUITOUTPUTDIR_NM)
            gp.CreateFolder_management(cfg.CENTRALITYBASEDIR,
                                        cfg.CIRCUITCONFIGDIR_NM)
            lu.clean_out_workspace(cfg.CORECENTRALITYGDB)

            s7.STEP7_calc_centrality()
            if not cfg.SAVECENTRALITYDIR:
                lu.delete_dir(cfg.CENTRALITYBASEDIR)

        if cfg.DOPINCH:
            if cfg.CWDCUTOFF > 0: # Negative values mean we're restarting
                gprint("Creating output folder: " + cfg.CIRCUITBASEDIR)
                lu.delete_dir(cfg.CIRCUITBASEDIR)
                lu.create_dir(cfg.CIRCUITBASEDIR)
                gp.CreateFolder_management(cfg.CIRCUITBASEDIR,
                                        cfg.CIRCUITOUTPUTDIR_NM)
                gp.CreateFolder_management(cfg.CIRCUITBASEDIR,
                                        cfg.CIRCUITCONFIGDIR_NM)

            s8.STEP8_calc_pinchpoints()            
            
            if not cfg.SAVE_TEMP_CIRCUIT_FILES:
                lu.delete_dir(cfg.SCRATCHDIR)
            if not cfg.SAVECIRCUITDIR:
                lu.delete_dir(cfg.CIRCUITBASEDIR)

        gprint('\nDONE!\n')

    # Return GEOPROCESSING specific errors
    except arcgisscripting.ExecuteError:
        lu.exit_with_geoproc_error(_SCRIPT_NAME)

    # Return any PYTHON or system specific errors
    except:
        lu.exit_with_python_error(_SCRIPT_NAME)
Example #4
0
def STEP8_calc_pinchpoints():
    """ Maps pinch points in Linkage Mapper corridors using Circuitscape
        given CWD calculations from s3_calcCwds.py.

    """
    try:
        lu.dashline(0)
        gprint('Running script ' + _SCRIPT_NAME)
        
        restartFlag = False
        if cfg.CWDCUTOFF < 0:
            cfg.CWDCUTOFF = cfg.CWDCUTOFF * -1
            restartFlag = True # Restart code in progress
        
        CSPATH = lu.get_cs_path()                
        outputGDB = path.join(cfg.OUTPUTDIR, path.basename(cfg.PINCHGDB))
        
        arcpy.OverWriteOutput = True
        arcpy.env.workspace = cfg.SCRATCHDIR
        arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
        arcpy.env.pyramid = "NONE"
        arcpy.env.rasterstatistics = "NONE"

        # set the analysis extent and cell size to that of the resistance
        # surface
        arcpy.env.extent = cfg.RESRAST
        arcpy.env.cellSize = cfg.RESRAST
        arcpy.snapraster = cfg.RESRAST

        resRaster = cfg.RESRAST
        arcpy.env.extent = "MINOF"

        
        minObject = arcpy.GetRasterProperties_management(resRaster, "MINIMUM") 
        rasterMin = float(str(minObject.getOutput(0)))
        if rasterMin <= 0:
            msg = ('Error: resistance raster cannot have 0 or negative values.')
            lu.raise_error(msg)
                
        if cfg.DO_ADJACENTPAIRS:
            prevLcpShapefile = lu.get_lcp_shapefile(None, thisStep = 8)
            if not arcpy.Exists(prevLcpShapefile):
                msg = ('Cannot find an LCP shapefile from step 5.  Please '
                        'rerun that step and any previous ones if necessary.')
                lu.raise_error(msg)

            # Remove lcp shapefile
            lcpShapefile = path.join(cfg.DATAPASSDIR, "lcpLines_s8.shp")
            lu.delete_data(lcpShapefile)

        inLinkTableFile = lu.get_prev_step_link_table(step=8)
        linkTable = lu.load_link_table(inLinkTableFile)
        numLinks = linkTable.shape[0]
        numCorridorLinks = lu.report_links(linkTable)
        if numCorridorLinks == 0:
            lu.dashline(1)
            msg =('\nThere are no linkages. Bailing.')
            lu.raise_error(msg)

        if linkTable.shape[1] < 16: # If linktable has no entries from prior
                                    # centrality or pinchpint analyses
            extraCols = npy.zeros((numLinks, 6), dtype="float64")
            linkTable = linkTable[:,0:10]
            linkTable = npy.append(linkTable, extraCols, axis=1)
            linkTable[:, cfg.LTB_LCPLEN] = -1
            linkTable[:, cfg.LTB_CWDEUCR] = -1
            linkTable[:, cfg.LTB_CWDPATHR] = -1
            linkTable[:, cfg.LTB_EFFRESIST] = -1
            linkTable[:, cfg.LTB_CWDTORR] = -1
            linkTable[:, cfg.LTB_CURRENT] = -1
            del extraCols

        # set up directories for circuit and circuit mosaic grids
        # Create output geodatabase
        if not arcpy.Exists(cfg.PINCHGDB):
            arcpy.CreateFileGDB_management(cfg.OUTPUTDIR,
                                            path.basename(cfg.PINCHGDB))

        mosaicRaster = path.join(cfg.CIRCUITBASEDIR, "current_mos" + tif)
        coresToProcess = npy.unique(
                                linkTable[:, cfg.LTB_CORE1:cfg.LTB_CORE2 + 1])
        maxCoreNum = max(coresToProcess)
        del coresToProcess

        lu.dashline(0)
        coreList = linkTable[:,cfg.LTB_CORE1:cfg.LTB_CORE2+1]
        coreList = npy.sort(coreList)
        #gprint('There are ' + str(len(npy.unique(coreList))) ' core areas.')

        INCIRCUITDIR = cfg.CIRCUITBASEDIR
        OUTCIRCUITDIR = path.join(cfg.CIRCUITBASEDIR,
                                  cfg.CIRCUITOUTPUTDIR_NM)
        CONFIGDIR = path.join(INCIRCUITDIR, cfg.CIRCUITCONFIGDIR_NM)

        # Cutoff value text to append to filenames
        cutoffText = str(cfg.CWDCUTOFF)
        if cutoffText[-6:] == '000000':
            cutoffText = cutoffText[0:-6]+'m' 
        elif cutoffText[-3:] == '000':
            cutoffText = cutoffText[0:-3]+'k' 

        if cfg.SQUARERESISTANCES:
            # Square resistance values
            squaredRaster = path.join(cfg.SCRATCHDIR,'res_sqr')
            arcpy.env.workspace = cfg.SCRATCHDIR
            arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
            outRas = Raster(resRaster) * Raster(resRaster)
            outRas.save(squaredRaster)
            resRaster = squaredRaster

        if cfg.DO_ADJACENTPAIRS:
            linkLoop = 0
            lu.dashline(1)
            gprint('Mapping pinch points in individual corridors \n'
                    'using Circuitscape.')
            lu.dashline(1)
            gprint('If you try to cancel your run and the Arc dialog hangs, ')
            gprint('you can kill Circuitscape by opening Windows Task Manager')
            gprint('and ending the cs_run.exe process.')                    
            lu.dashline(2)

            for x in range(0,numLinks):            
                linkId = str(int(linkTable[x,cfg.LTB_LINKID]))
                if not (linkTable[x,cfg.LTB_LINKTYPE] > 0):
                    continue
                linkLoop = linkLoop + 1
                linkDir = path.join(cfg.SCRATCHDIR, 'link' + linkId)
                if restartFlag == True and path.exists(linkDir):
                    gprint('continuing')
                    continue
                restartFlag = False
                lu.create_dir(linkDir)
                start_time1 = time.clock()

                # source and target cores
                corex=int(coreList[x,0])
                corey=int(coreList[x,1])

                # Get cwd rasters for source and target cores
                cwdRaster1 = lu.get_cwd_path(corex)
                cwdRaster2 = lu.get_cwd_path(corey)

                lccNormRaster = path.join(linkDir, 'lcc_norm')
                arcpy.env.extent = "MINOF"

                link = lu.get_links_from_core_pairs(linkTable, corex,
                                                    corey)
                lcDist = float(linkTable[link,cfg.LTB_CWDIST])

                # Normalized lcc rasters are created by adding cwd rasters
                # and subtracting the least cost distance between them.
                outRas = Raster(cwdRaster1) + Raster(cwdRaster2) - lcDist
                outRas.save(lccNormRaster)

                #create raster mask
                resMaskRaster = path.join(linkDir, 'res_mask'+tif)

                #create raster mask
                outCon = arcpy.sa.Con(Raster(lccNormRaster) <= cfg.CWDCUTOFF, 1)
                outCon.save(resMaskRaster)

                # Convert to poly.  Use as mask to clip resistance raster.
                resMaskPoly = path.join(linkDir,
                                        'res_mask_poly.shp')
                arcpy.RasterToPolygon_conversion(resMaskRaster, resMaskPoly,
                                              "NO_SIMPLIFY")
                arcpy.env.extent = resMaskPoly

                # Includes 0 values in some cases with CP LI model if tif
                # so using ESRI Grid format
                resClipRasterMasked = path.join(linkDir,
                                                'res_clip_m') 
                # Extract masked resistance raster.  
                # Needs to be float to get export to npy to work.
                outRas = arcpy.sa.ExtractByMask(resRaster, resMaskPoly) + 0.0 
                outRas.save(resClipRasterMasked)
               
                resNpyFN = 'resistances_link_' + linkId + '.npy'
                resNpyFile = path.join(INCIRCUITDIR, resNpyFN)
                numElements, numResistanceNodes = export_ras_to_npy(resClipRasterMasked,
                                                          resNpyFile)
                
                totMem, availMem = lu.get_mem()
                # gprint('Total memory: str(totMem))
                if numResistanceNodes / availMem > 2000000:
                    lu.dashline(1)
                    gwarn('Warning:')
                    gwarn('Circuitscape can only solve 2-3 million nodes')
                    gwarn('per gigabyte of available RAM. \nTotal physical RAM'
                            ' on your machine is ~' + str(totMem) 
                            + ' GB. \nAvailable memory is ~'+ str(availMem) 
                            + ' GB. \nYour resistance raster has '
                            + str(numResistanceNodes) + ' nodes.')                                                          
                    lu.dashline(2)
                corePairRaster = path.join(linkDir, 'core_pairs'+tif)
                arcpy.env.extent = resClipRasterMasked

                # Next result needs to be floating pt for numpy export
                outCon = arcpy.sa.Con(Raster(cwdRaster1) == 0, corex,
                            arcpy.sa.Con(Raster(cwdRaster2) == 0, corey + 0.0))
                outCon.save(corePairRaster)

                coreNpyFN = 'cores_link_' + linkId + '.npy'
                coreNpyFile = path.join(INCIRCUITDIR, coreNpyFN)
                numElements, numNodes = export_ras_to_npy(corePairRaster,
                                                          coreNpyFile)

                arcpy.env.extent = "MINOF"

                # Set circuitscape options and call
                options = lu.setCircuitscapeOptions()
                if cfg.WRITE_VOLT_MAPS == True:
                    options['write_volt_maps']=True
                options['habitat_file'] = resNpyFile
                
                # if int(linkId) > 2:
                    # options['habitat_file'] = 'c:\\test.dummy'
                                
                options['point_file'] = coreNpyFile
                options['set_focal_node_currents_to_zero']=True
                outputFN = 'Circuitscape_link' + linkId + '.out'
                options['output_file'] = path.join(OUTCIRCUITDIR, outputFN)
                if numElements > 250000:
                    options['print_timings']=True
                configFN = 'pinchpoint_config' + linkId + '.ini'

                outConfigFile = path.join(CONFIGDIR, configFN)
                lu.writeCircuitscapeConfigFile(outConfigFile, options)                    
                gprint('Processing link ID #' + str(linkId) + '. Resistance map'
                        ' has ' + str(int(numResistanceNodes)) + ' nodes.') 

                memFlag = call_circuitscape(CSPATH, outConfigFile)
                      
                currentFN = ('Circuitscape_link' + linkId 
                            + '_cum_curmap.npy')
                currentMap = path.join(OUTCIRCUITDIR, currentFN)
                
                if not arcpy.Exists(currentMap):
                    print_failure(numResistanceNodes, memFlag, 10)
                    numElements, numNodes = export_ras_to_npy(
                                                resClipRasterMasked,resNpyFile)
                    memFlag = call_circuitscape(CSPATH, outConfigFile)

                    currentFN = ('Circuitscape_link' + linkId 
                                + '_cum_curmap.npy')
                    currentMap = path.join(OUTCIRCUITDIR, currentFN)
                
                if not arcpy.Exists(currentMap):                
                    msg = ('\nCircuitscape failed. See error information above.')
                    arcpy.AddError(msg)
                    lu.write_log(msg)
                    exit(1)

                # Either set core areas to nodata in current map or
                # divide each by its radius
                currentRaster = path.join(linkDir, "current" + tif)
                import_npy_to_ras(currentMap,corePairRaster,currentRaster)
                
                if cfg.WRITE_VOLT_MAPS == True:
                    voltFN = ('Circuitscape_link' + linkId + '_voltmap_'
                           + str(corex) + '_'+str(corey) + '.npy')
                    voltMap = path.join(OUTCIRCUITDIR, voltFN)
                    voltRaster = path.join(outputGDB,
                             cfg.PREFIX + "_voltMap_"+ str(corex) + '_'+str(corey))                
                    import_npy_to_ras(voltMap,corePairRaster,voltRaster)
                    gprint('Building output statistics and pyramids '
                                   'for voltage raster\n')
                    lu.build_stats(voltRaster) 
                    
                arcpy.env.extent = currentRaster

                if SETCORESTONULL:
                    # Set core areas to NoData in current map for color ramping
                    currentRaster2 = currentRaster + '2' + tif
                    outCon = arcpy.sa.Con(arcpy.sa.IsNull(Raster
                                      (corePairRaster)), Raster(currentRaster))
                    outCon.save(currentRaster2)
                    currentRaster = currentRaster2
                arcpy.env.extent = "MAXOF"
                if linkLoop == 1:
                    lu.delete_data(mosaicRaster)
                    @retry(10)
                    def copyRas2():
                        arcpy.CopyRaster_management(currentRaster,
                                                    mosaicRaster)
                    copyRas2()
                else:
                    @retry(10)
                    def mosaicRas():                
                        arcpy.Mosaic_management(currentRaster,
                                         mosaicRaster, "MAXIMUM", "MATCH")
                    mosaicRas()
                    
                resistancesFN = ('Circuitscape_link' + linkId
                            + '_resistances_3columns.out')

                resistancesFile = path.join(OUTCIRCUITDIR,resistancesFN)
                resistances = npy.loadtxt(resistancesFile,
                                          dtype = 'Float64', comments='#')

                resistance = float(str(arcpy.env.cellSize)) * resistances[2]
                linkTable[link,cfg.LTB_EFFRESIST] = resistance

                # Ratio
                if not cfg.SQUARERESISTANCES:
                    linkTable[link,cfg.LTB_CWDTORR] = (linkTable[link,
                           cfg.LTB_CWDIST] / linkTable[link,cfg.LTB_EFFRESIST])
                # Clean up
                if cfg.SAVE_TEMP_CIRCUIT_FILES == False:
                    lu.delete_file(coreNpyFile)
                    coreNpyBase, extension = path.splitext(coreNpyFile)
                    lu.delete_data(coreNpyBase + '.hdr')                    
                    lu.delete_file(resNpyFile)
                    resNpyBase, extension = path.splitext(resNpyFile)
                    lu.delete_data(resNpyBase + '.hdr')                    
                    lu.delete_file(currentMap)
                    curMapBase, extension = path.splitext(currentMap)
                    lu.delete_data(curMapBase + '.hdr')
                    lu.delete_data(currentRaster) 
                    lu.clean_out_workspace(linkDir)
                    lu.delete_dir(linkDir) 
                gprint('Finished with link ID #' + str(linkId) + '. ' + 
                        str(linkLoop) + ' out of ' + str(numCorridorLinks) + 
                        ' links have been processed.')
                start_time1 = lu.elapsed_time(start_time1)
                
            outputRaster = path.join(outputGDB, cfg.PREFIX + 
                                     "_current_adjacentPairs_" + cutoffText)
            lu.delete_data(outputRaster)
            
            @retry(10)
            def copyRas():
                arcpy.CopyRaster_management(mosaicRaster, outputRaster)
            copyRas()

            gprint('Building output statistics and pyramids '
                                  'for corridor pinch point raster\n')
            lu.build_stats(outputRaster)
            
            finalLinkTable = lu.update_lcp_shapefile(linkTable, lastStep=5,
                                                      thisStep=8)

            linkTableFile = path.join(cfg.DATAPASSDIR, "linkTable_s5_plus.csv")
            lu.write_link_table(finalLinkTable, linkTableFile, inLinkTableFile)
            linkTableFinalFile = path.join(cfg.OUTPUTDIR, cfg.PREFIX + 
                                           "_linkTable_s5_plus.csv")
            lu.write_link_table(finalLinkTable,
                                linkTableFinalFile, inLinkTableFile)
            gprint('Copy of linkTable written to '+
                              linkTableFinalFile)
            #fixme: update sticks?

            gprint('Creating shapefiles with linework for links.')
            lu.write_link_maps(linkTableFinalFile, step=8)

            # Copy final link maps to gdb.
            lu.copy_final_link_maps(step=8)

            lu.delete_data(mosaicRaster)

        if not cfg.DO_ALLPAIRS:
            # Clean up temporary files
            if not cfg.SAVECURRENTMAPS:
                lu.delete_dir(OUTCIRCUITDIR)
            return

        lu.dashline(1)
        gprint('Mapping global pinch points among all\n'
                'core area pairs using Circuitscape.')                   
                
        if cfg.ALL_PAIR_SCENARIO=='pairwise':
            gprint('Circuitscape will be run in PAIRWISE mode.')
                        
        else:
            gprint('Circuitscape will be run in ALL-TO-ONE mode.')     
        arcpy.env.workspace = cfg.SCRATCHDIR
        arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
        arcpy.env.extent = cfg.RESRAST
        arcpy.env.cellSize = cfg.RESRAST

        S8CORE_RAS = "s8core_ras"
        s8CoreRasPath = path.join(cfg.SCRATCHDIR,S8CORE_RAS)

        arcpy.FeatureToRaster_conversion(cfg.COREFC, cfg.COREFN,
                                         s8CoreRasPath, arcpy.env.cellSize)
        binaryCoreRaster = path.join(cfg.SCRATCHDIR,"core_ras_bin")

        # The following commands cause file lock problems on save.  using gp
        # instead.
        # outCon = arcpy.sa.Con(S8CORE_RAS, 1, "#", "VALUE > 0")
        # outCon.save(binaryCoreRaster)
        # gp.Con_sa(s8CoreRasPath, 1, binaryCoreRaster, "#", "VALUE > 0")
        outCon = arcpy.sa.Con(Raster(s8CoreRasPath) > 0, 1)
        outCon.save(binaryCoreRaster)
        s5corridorRas = path.join(cfg.OUTPUTGDB,cfg.PREFIX + "_corridors")
        
        if not arcpy.Exists(s5corridorRas):
            s5corridorRas = path.join(cfg.OUTPUTGDB,cfg.PREFIX + 
                                      "_lcc_mosaic_int")

        outCon = arcpy.sa.Con(Raster(s5corridorRas) <= cfg.CWDCUTOFF, Raster(
                              resRaster), arcpy.sa.Con(Raster(
                              binaryCoreRaster) > 0, Raster(resRaster)))

        resRasClipPath = path.join(cfg.SCRATCHDIR,'res_ras_clip')
        outCon.save(resRasClipPath)

        arcpy.env.cellSize = resRasClipPath
        arcpy.env.extent = resRasClipPath
        s8CoreRasClipped = s8CoreRasPath + '_c'

        # Produce core raster with same extent as clipped resistance raster
        # added to ensure correct data type- nodata values were positive for 
        # cores otherwise
        outCon = arcpy.sa.Con(arcpy.sa.IsNull(Raster(s8CoreRasPath)), 
                              -9999, Raster(s8CoreRasPath))  
        outCon.save(s8CoreRasClipped)

        resNpyFN = 'resistances.npy'
        resNpyFile = path.join(INCIRCUITDIR, resNpyFN)
        numElements, numResistanceNodes = export_ras_to_npy(resRasClipPath,resNpyFile)

        totMem, availMem = lu.get_mem()
        # gprint('Total memory: str(totMem))
        if numResistanceNodes / availMem > 2000000:
            lu.dashline(1)
            gwarn('Warning:')
            gwarn('Circuitscape can only solve 2-3 million nodes')
            gwarn('per gigabyte of available RAM. \nTotal physical RAM '
                    'on your machine is ~' + str(totMem)
                    + ' GB. \nAvailable memory is ~'+ str(availMem)
                    + ' GB. \nYour resistance raster has '
                    + str(numResistanceNodes) + ' nodes.')   
            lu.dashline(0)

        coreNpyFN = 'cores.npy'
        coreNpyFile = path.join(INCIRCUITDIR, coreNpyFN)
        numElements, numNodes = export_ras_to_npy(s8CoreRasClipped,coreNpyFile)

        arcpy.env.extent = "MINOF"

        options = lu.setCircuitscapeOptions()
        options['scenario']=cfg.ALL_PAIR_SCENARIO
        options['habitat_file'] = resNpyFile
        options['point_file'] = coreNpyFile
        options['set_focal_node_currents_to_zero']=True
        outputFN = 'Circuitscape.out'
        options['output_file'] = path.join(OUTCIRCUITDIR, outputFN)
        options['print_timings']=True
        configFN = 'pinchpoint_allpair_config.ini'
        outConfigFile = path.join(CONFIGDIR, configFN)
        lu.writeCircuitscapeConfigFile(outConfigFile, options)
        gprint('\nResistance map has ' + str(int(numResistanceNodes)) + ' nodes.') 
        lu.dashline(1)
        gprint('If you try to cancel your run and the Arc dialog hangs, ')
        gprint('you can kill Circuitscape by opening Windows Task Manager')
        gprint('and ending the cs_run.exe process.')             
        lu.dashline(0)
        
        call_circuitscape(CSPATH, outConfigFile)
        # test = subprocess.call([CSPATH, outConfigFile],
                               # creationflags = subprocess.CREATE_NEW_CONSOLE)

        if options['scenario']=='pairwise':
            rasterSuffix =  "_current_allPairs_" + cutoffText
                        
        else:
            rasterSuffix =  "_current_allToOne_" + cutoffText

        currentFN = 'Circuitscape_cum_curmap.npy'
        currentMap = path.join(OUTCIRCUITDIR, currentFN)
        outputRaster = path.join(outputGDB, cfg.PREFIX + rasterSuffix)
        currentRaster = path.join(cfg.SCRATCHDIR, "current")

        try:
            import_npy_to_ras(currentMap,resRasClipPath,outputRaster)
        except:
            lu.dashline(1)
            msg = ('ERROR: Circuitscape failed. \n'
                  'Note: Circuitscape can only solve 2-3 million nodes'
                  '\nper gigabyte of available RAM. The resistance '
                  '\nraster for the last corridor had '
                  + str(numResistanceNodes) + ' nodes.\n\nResistance '
                  'raster values that vary by >6 orders of \nmagnitude'
                  ' can also cause failures, as can a mismatch in '
                  '\ncore area and resistance raster extents.')
            arcpy.AddError(msg)
            lu.write_log(msg)
            exit(1)

        #set core areas to nodata 
        if SETCORESTONULL:                  
            # Set core areas to NoData in current map for color ramping
            outputRasterND = outputRaster + '_noDataCores' 
            outCon = arcpy.sa.SetNull(Raster(s8CoreRasClipped) > 0, 
                                      Raster(outputRaster))   
            outCon.save(outputRasterND)                

        gprint('\nBuilding output statistics and pyramids ' 
                'for centrality raster.')        
        lu.build_stats(outputRaster)
        lu.build_stats(outputRasterND)

        # Clean up temporary files
        if not cfg.SAVECURRENTMAPS:
            lu.delete_dir(OUTCIRCUITDIR)

    # Return GEOPROCESSING specific errors
    except arcpy.ExecuteError:
        lu.dashline(1)
        gprint('****Failed in step 8. Details follow.****')
        lu.exit_with_geoproc_error(_SCRIPT_NAME)

    # Return any PYTHON or system specific errors
    except:
        lu.dashline(1)
        gprint('****Failed in step 8. Details follow.****')
        lu.exit_with_python_error(_SCRIPT_NAME)
Example #5
0
            def doRadiusLoop():
                linkTable = linkTableTemp.copy()
                startTime = time.clock()
                randomerror()
                linkLoop = 0
                pctDone = 0
                gprint('\nMapping barriers at a radius of ' + str(radius) +
                       ' ' + str(mapUnits))
                if cfg.SUM_BARRIERS:
                    gprint('using SUM method')
                else:
                    gprint('using MAXIMUM method')
                if numCorridorLinks > 1:
                    gprint('0 percent done')
                lastMosaicRaster = None
                lastMosaicRasterPct = None
                for x in range(0, numLinks):
                    pctDone = lu.report_pct_done(linkLoop, numCorridorLinks,
                                                 pctDone)
                    linkId = str(int(linkTable[x, cfg.LTB_LINKID]))
                    if ((linkTable[x, cfg.LTB_LINKTYPE] > 0)
                            and (linkTable[x, cfg.LTB_LINKTYPE] < 1000)):
                        linkLoop = linkLoop + 1
                        # source and target cores
                        corex = int(coreList[x, 0])
                        corey = int(coreList[x, 1])

                        # Get cwd rasters for source and target cores
                        cwdRaster1 = lu.get_cwd_path(corex)
                        cwdRaster2 = lu.get_cwd_path(corey)

                        # Mask out areas above CWD threshold
                        cwdTemp1 = None
                        cwdTemp2 = None
                        if cfg.BARRIER_CWD_THRESH is not None:
                            if x == 1:
                                lu.dashline(1)
                                gprint('  Using CWD threshold of ' +
                                       str(cfg.BARRIER_CWD_THRESH) +
                                       ' map units.')
                            arcpy.env.extent = cfg.RESRAST
                            arcpy.env.cellSize = cfg.RESRAST
                            arcpy.env.snapRaster = cfg.RESRAST
                            cwdTemp1 = path.join(cfg.SCRATCHDIR,
                                                 "tmp" + str(corex))
                            outCon = arcpy.sa.Con(
                                cwdRaster1 < float(cfg.BARRIER_CWD_THRESH),
                                cwdRaster1)
                            outCon.save(cwdTemp1)
                            cwdRaster1 = cwdTemp1
                            cwdTemp2 = path.join(cfg.SCRATCHDIR,
                                                 "tmp" + str(corey))
                            outCon = arcpy.sa.Con(
                                cwdRaster2 < float(cfg.BARRIER_CWD_THRESH),
                                cwdRaster2)
                            outCon.save(cwdTemp2)
                            cwdRaster2 = cwdTemp2

                        focalRaster1 = lu.get_focal_path(corex, radius)
                        focalRaster2 = lu.get_focal_path(corey, radius)

                        link = lu.get_links_from_core_pairs(
                            linkTable, corex, corey)
                        lcDist = float(linkTable[link, cfg.LTB_CWDIST])

                        # Detect barriers at radius using neighborhood stats
                        # Create the Neighborhood Object
                        innerRadius = radius - 1
                        outerRadius = radius

                        dia = 2 * radius
                        InNeighborhood = ("ANNULUS " + str(innerRadius) + " " +
                                          str(outerRadius) + " MAP")

                        @retry(10)
                        def execFocal():
                            randomerror()
                            # Execute FocalStatistics
                            if not path.exists(focalRaster1):
                                arcpy.env.extent = cwdRaster1
                                outFocalStats = arcpy.sa.FocalStatistics(
                                    cwdRaster1, InNeighborhood, "MINIMUM",
                                    "DATA")
                                if setCoresToNull:
                                    outFocalStats2 = arcpy.sa.Con(
                                        outFocalStats > 0, outFocalStats
                                    )  # Set areas overlapping cores to NoData xxx
                                    outFocalStats2.save(focalRaster1)  #xxx
                                else:
                                    outFocalStats.save(focalRaster1)  #xxx
                                arcpy.env.extent = cfg.RESRAST

                            if not path.exists(focalRaster2):
                                arcpy.env.extent = cwdRaster2
                                outFocalStats = arcpy.sa.FocalStatistics(
                                    cwdRaster2, InNeighborhood, "MINIMUM",
                                    "DATA")
                                if setCoresToNull:
                                    outFocalStats2 = arcpy.sa.Con(
                                        outFocalStats > 0, outFocalStats
                                    )  # Set areas overlapping cores to NoData xxx
                                    outFocalStats2.save(focalRaster2)  #xxx
                                else:
                                    outFocalStats.save(focalRaster2)  #xxx

                                arcpy.env.extent = cfg.RESRAST

                        execFocal()

                        lu.delete_data(cwdTemp1)
                        lu.delete_data(cwdTemp2)

                        barrierRaster = path.join(
                            cbarrierdir, "b" + str(radius) + "_" + str(corex) +
                            "_" + str(corey) + '.tif')

                        if cfg.SUM_BARRIERS:  # Need to set nulls to 0, also
                            # create trim rasters as we go

                            outRas = ((lcDist - Raster(focalRaster1) -
                                       Raster(focalRaster2) - dia) / dia)
                            outCon = arcpy.sa.Con(IsNull(outRas), 0, outRas)
                            outCon2 = arcpy.sa.Con(outCon < 0, 0, outCon)
                            outCon2.save(barrierRaster)

                            # Execute FocalStatistics to fill out search radii
                            InNeighborhood = "CIRCLE " + str(
                                outerRadius) + " MAP"
                            fillRaster = path.join(
                                cbarrierdir, "b" + str(radius) + "_" +
                                str(corex) + "_" + str(corey) + "_fill.tif")
                            outFocalStats = arcpy.sa.FocalStatistics(
                                barrierRaster, InNeighborhood, "MAXIMUM",
                                "DATA")
                            outFocalStats.save(fillRaster)

                            if cfg.WRITE_TRIM_RASTERS:
                                trmRaster = path.join(
                                    cbarrierdir,
                                    "b" + str(radius) + "_" + str(corex) +
                                    "_" + str(corey) + "_trim.tif")
                                rasterList = [fillRaster, resistFillRaster]
                                outCellStatistics = arcpy.sa.CellStatistics(
                                    rasterList, "MINIMUM")
                                outCellStatistics.save(trmRaster)

                        else:
                            #Calculate potential benefit per map unit restored
                            @retry(10)
                            def calcBen():
                                randomerror()
                                outRas = ((lcDist - Raster(focalRaster1) -
                                           Raster(focalRaster2) - dia) / dia)
                                outRas.save(barrierRaster)

                            calcBen()

                        if cfg.WRITE_PCT_RASTERS:
                            #Calculate PERCENT potential benefit per unit restored
                            barrierRasterPct = path.join(
                                cbarrierdir, "b" + str(radius) + "_" +
                                str(corex) + "_" + str(corey) + '_pct.tif')

                            @retry(10)
                            def calcBenPct():
                                randomerror()
                                outras = (100 *
                                          (Raster(barrierRaster) / lcDist))
                                outras.save(barrierRasterPct)

                            calcBenPct()

                        # Mosaic barrier results across core area pairs
                        mosaicDir = path.join(
                            cfg.SCRATCHDIR,
                            'mos' + str(radId) + '_' + str(x + 1))
                        lu.create_dir(mosaicDir)

                        mosFN = 'mos_temp'
                        tempMosaicRaster = path.join(mosaicDir, mosFN)
                        tempMosaicRasterTrim = path.join(
                            mosaicDir, 'mos_temp_trm')
                        arcpy.env.workspace = mosaicDir
                        if linkLoop == 1:
                            #If this is the first grid then copy rather than mosaic
                            arcpy.CopyRaster_management(
                                barrierRaster, tempMosaicRaster)
                            if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                                arcpy.CopyRaster_management(
                                    trmRaster, tempMosaicRasterTrim)

                        else:
                            if cfg.SUM_BARRIERS:
                                outCon = arcpy.sa.Con(
                                    Raster(barrierRaster) < 0,
                                    lastMosaicRaster,
                                    Raster(barrierRaster) +
                                    Raster(lastMosaicRaster))
                                outCon.save(tempMosaicRaster)
                                if cfg.WRITE_TRIM_RASTERS:
                                    outCon = arcpy.sa.Con(
                                        Raster(trmRaster) < 0,
                                        lastMosaicRasterTrim,
                                        Raster(trmRaster) +
                                        Raster(lastMosaicRasterTrim))
                                    outCon.save(tempMosaicRasterTrim)

                            else:
                                rasterString = ('"' + barrierRaster + ";" +
                                                lastMosaicRaster + '"')

                                @retry(10)
                                def mosaicToNew():
                                    randomerror()
                                    arcpy.MosaicToNewRaster_management(
                                        rasterString, mosaicDir, mosFN, "",
                                        "32_BIT_FLOAT", arcpy.env.cellSize,
                                        "1", "MAXIMUM", "MATCH")

                                mosaicToNew()
                                # gprint(str(corex)+'0'+str(corey))

                        if linkLoop > 1:  #Clean up from previous loop
                            lu.delete_data(lastMosaicRaster)
                            lastMosaicDir = path.dirname(lastMosaicRaster)
                            lu.clean_out_workspace(lastMosaicDir)
                            lu.delete_dir(lastMosaicDir)

                        lastMosaicRaster = tempMosaicRaster
                        if cfg.WRITE_TRIM_RASTERS:
                            lastMosaicRasterTrim = tempMosaicRasterTrim
                        if cfg.WRITE_PCT_RASTERS:
                            mosPctFN = 'mos_temp_pct'
                            mosaicDirPct = path.join(
                                cfg.SCRATCHDIR,
                                'mosP' + str(radId) + '_' + str(x + 1))
                            lu.create_dir(mosaicDirPct)
                            tempMosaicRasterPct = path.join(
                                mosaicDirPct, mosPctFN)
                            if linkLoop == 1:
                                # If this is the first grid then copy
                                # rather than mosaic
                                if cfg.SUM_BARRIERS:
                                    outCon = arcpy.sa.Con(
                                        Raster(barrierRasterPct) < 0, 0,
                                        arcpy.sa.Con(IsNull(barrierRasterPct),
                                                     0, barrierRasterPct))
                                    outCon.save(tempMosaicRasterPct)
                                else:
                                    arcpy.CopyRaster_management(
                                        barrierRasterPct, tempMosaicRasterPct)

                            else:
                                if cfg.SUM_BARRIERS:

                                    @retry(10)
                                    def sumBarriers():
                                        randomerror()
                                        outCon = arcpy.sa.Con(
                                            Raster(barrierRasterPct) < 0,
                                            lastMosaicRasterPct,
                                            Raster(barrierRasterPct) +
                                            Raster(lastMosaicRasterPct))
                                        outCon.save(tempMosaicRasterPct)

                                    sumBarriers()
                                else:
                                    rasterString = ('"' + barrierRasterPct +
                                                    ";" + lastMosaicRasterPct +
                                                    '"')

                                    @retry(10)
                                    def maxBarriers():
                                        randomerror()
                                        arcpy.MosaicToNewRaster_management(
                                            rasterString, mosaicDirPct,
                                            mosPctFN, "", "32_BIT_FLOAT",
                                            arcpy.env.cellSize, "1", "MAXIMUM",
                                            "MATCH")

                                    maxBarriers()

                            if linkLoop > 1:  #Clean up from previous loop
                                lu.delete_data(lastMosaicRasterPct)
                                lastMosaicDirPct = path.dirname(
                                    lastMosaicRasterPct)
                                lu.clean_out_workspace(lastMosaicDirPct)
                                lu.delete_dir(lastMosaicDirPct)

                            # lu.delete_data(lastMosaicRasterPct)
                            lastMosaicRasterPct = tempMosaicRasterPct

                        if not cfg.SAVEBARRIERRASTERS:
                            lu.delete_data(barrierRaster)
                            if cfg.WRITE_PCT_RASTERS:
                                lu.delete_data(barrierRasterPct)
                            if cfg.WRITE_TRIM_RASTERS:
                                lu.delete_data(trmRaster)

                        # Temporarily disable links in linktable -
                        # don't want to mosaic them twice
                        for y in range(x + 1, numLinks):
                            corex1 = int(coreList[y, 0])
                            corey1 = int(coreList[y, 1])
                            if corex1 == corex and corey1 == corey:
                                linkTable[y, cfg.LTB_LINKTYPE] = (
                                    linkTable[y, cfg.LTB_LINKTYPE] + 1000)
                            elif corex1 == corey and corey1 == corex:
                                linkTable[y, cfg.LTB_LINKTYPE] = (
                                    linkTable[y, cfg.LTB_LINKTYPE] + 1000)

                if numCorridorLinks > 1 and pctDone < 100:
                    gprint('100 percent done')
                gprint('Summarizing barrier data for search radius.')
                #rows that were temporarily disabled
                rows = npy.where(linkTable[:, cfg.LTB_LINKTYPE] > 1000)
                linkTable[rows, cfg.LTB_LINKTYPE] = (
                    linkTable[rows, cfg.LTB_LINKTYPE] - 1000)

                # -----------------------------------------------------------------

                # Set negative values to null or zero and write geodatabase.
                mosaicFN = (PREFIX + "_BarrierCenters" + sumSuffix + "_Rad" +
                            str(radius))
                mosaicRaster = path.join(cfg.BARRIERGDB, mosaicFN)
                arcpy.env.extent = cfg.RESRAST

                # if setCoresToNull:
                # outCon = arcpy.sa.Con(Raster(tempMosaicRaster) < 0, 0,
                # tempMosaicRaster) #xxx
                # outCon.save(mosaicRaster) #xxx
                # else:
                outSetNull = arcpy.sa.SetNull(tempMosaicRaster,
                                              tempMosaicRaster,
                                              "VALUE < 0")  #xxx orig
                outSetNull.save(mosaicRaster)

                lu.delete_data(tempMosaicRaster)

                if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    mosaicFN = (PREFIX + "_BarrierCircles_RBMin" + sumSuffix +
                                "_Rad" + str(radius))
                    mosaicRasterTrim = path.join(cfg.BARRIERGDB, mosaicFN)
                    arcpy.CopyRaster_management(tempMosaicRasterTrim,
                                                mosaicRasterTrim)
                    lu.delete_data(tempMosaicRaster)

                if cfg.WRITE_PCT_RASTERS:
                    # Do same for percent raster
                    mosaicPctFN = (PREFIX + "_BarrierCenters_Pct" + sumSuffix +
                                   "_Rad" + str(radius))
                    arcpy.env.extent = cfg.RESRAST
                    outSetNull = arcpy.sa.SetNull(tempMosaicRasterPct,
                                                  tempMosaicRasterPct,
                                                  "VALUE < 0")
                    mosaicRasterPct = path.join(cfg.BARRIERGDB, mosaicPctFN)
                    outSetNull.save(mosaicRasterPct)
                    lu.delete_data(tempMosaicRasterPct)

                # 'Grow out' maximum restoration gain to
                # neighborhood size for display
                InNeighborhood = "CIRCLE " + str(outerRadius) + " MAP"
                # Execute FocalStatistics
                fillRasterFN = "barriers_fill" + str(outerRadius) + tif
                fillRaster = path.join(cfg.BARRIERBASEDIR, fillRasterFN)
                outFocalStats = arcpy.sa.FocalStatistics(
                    mosaicRaster, InNeighborhood, "MAXIMUM", "DATA")
                outFocalStats.save(fillRaster)

                if cfg.WRITE_PCT_RASTERS:
                    # Do same for percent raster
                    fillRasterPctFN = "barriers_fill_pct" + str(
                        outerRadius) + tif
                    fillRasterPct = path.join(cfg.BARRIERBASEDIR,
                                              fillRasterPctFN)
                    outFocalStats = arcpy.sa.FocalStatistics(
                        mosaicRasterPct, InNeighborhood, "MAXIMUM", "DATA")
                    outFocalStats.save(fillRasterPct)

                #Place copies of filled rasters in output geodatabase
                arcpy.env.workspace = cfg.BARRIERGDB
                fillRasterFN = (PREFIX + "_BarrrierCircles" + sumSuffix +
                                "_Rad" + str(outerRadius))
                arcpy.CopyRaster_management(fillRaster, fillRasterFN)
                if cfg.WRITE_PCT_RASTERS:
                    fillRasterPctFN = (PREFIX + "_BarrrierCircles_Pct" +
                                       sumSuffix + "_Rad" + str(outerRadius))
                    arcpy.CopyRaster_management(fillRasterPct, fillRasterPctFN)

                if not cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    # Create pared-down version of filled raster- remove pixels
                    # that don't need restoring by allowing a pixel to only
                    # contribute its resistance value to restoration gain
                    outRasterFN = "barriers_trm" + str(outerRadius) + tif
                    outRaster = path.join(cfg.BARRIERBASEDIR, outRasterFN)
                    rasterList = [fillRaster, resistFillRaster]
                    outCellStatistics = arcpy.sa.CellStatistics(
                        rasterList, "MINIMUM")
                    outCellStatistics.save(outRaster)

                    #SECOND ROUND TO CLIP BY DATA VALUES IN BARRIER RASTER
                    outRaster2FN = ("barriers_trm" + sumSuffix +
                                    str(outerRadius) + "_2" + tif)
                    outRaster2 = path.join(cfg.BARRIERBASEDIR, outRaster2FN)
                    output = arcpy.sa.Con(IsNull(fillRaster), fillRaster,
                                          outRaster)
                    output.save(outRaster2)
                    outRasterFN = (PREFIX + "_BarrierCircles_RBMin" +
                                   sumSuffix + "_Rad" + str(outerRadius))

                    outRasterPath = path.join(cfg.BARRIERGDB, outRasterFN)
                    arcpy.CopyRaster_management(outRaster2, outRasterFN)
                randomerror()
                startTime = lu.elapsed_time(startTime)
Example #6
0
            def doRadiusLoop():
                linkTable = linkTableTemp.copy()
                startTime = time.clock()
                randomerror()
                linkLoop = 0
                pctDone = 0
                gprint('\nMapping barriers at a radius of ' + str(radius) +
                       ' ' + str(mapUnits))             
                if cfg.SUM_BARRIERS:  
                    gprint('using SUM method')
                else:
                    gprint('using MAXIMUM method')                   
                if numCorridorLinks > 1:
                    gprint('0 percent done')
                lastMosaicRaster = None
                lastMosaicRasterPct = None
                for x in range(0,numLinks):
                    pctDone = lu.report_pct_done(linkLoop, numCorridorLinks,
                                                pctDone)
                    linkId = str(int(linkTable[x,cfg.LTB_LINKID]))
                    if ((linkTable[x,cfg.LTB_LINKTYPE] > 0) and
                       (linkTable[x,cfg.LTB_LINKTYPE] < 1000)):
                        linkLoop = linkLoop + 1
                        # source and target cores
                        corex=int(coreList[x,0])
                        corey=int(coreList[x,1])

                        # Get cwd rasters for source and target cores
                        cwdRaster1 = lu.get_cwd_path(corex)
                        cwdRaster2 = lu.get_cwd_path(corey)
                        
                        # Mask out areas above CWD threshold
                        cwdTemp1 = None
                        cwdTemp2 = None
                        if cfg.BARRIER_CWD_THRESH is not None:
                            if x == 1:
                                lu.dashline(1)
                                gprint('  Using CWD threshold of ' + str(cfg.BARRIER_CWD_THRESH) + ' map units.')
                            arcpy.env.extent = cfg.RESRAST
                            arcpy.env.cellSize = cfg.RESRAST
                            arcpy.env.snapRaster = cfg.RESRAST
                            cwdTemp1 = path.join(cfg.SCRATCHDIR, "tmp"+str(corex))
                            outCon = arcpy.sa.Con(cwdRaster1 < float(cfg.BARRIER_CWD_THRESH),cwdRaster1)
                            outCon.save(cwdTemp1)
                            cwdRaster1 = cwdTemp1
                            cwdTemp2 = path.join(cfg.SCRATCHDIR, "tmp"+str(corey))
                            outCon = arcpy.sa.Con(cwdRaster2 < float(cfg.BARRIER_CWD_THRESH),cwdRaster2)
                            outCon.save(cwdTemp2)
                            cwdRaster2 = cwdTemp2                        
                        
                        focalRaster1 = lu.get_focal_path(corex,radius)
                        focalRaster2 = lu.get_focal_path(corey,radius)
                                                                     
                        link = lu.get_links_from_core_pairs(linkTable,
                                                            corex, corey)
                        lcDist = float(linkTable[link,cfg.LTB_CWDIST])
                        
                        # Detect barriers at radius using neighborhood stats
                        # Create the Neighborhood Object
                        innerRadius = radius - 1
                        outerRadius = radius

                        dia = 2 * radius
                        InNeighborhood = ("ANNULUS " + str(innerRadius) + " " +
                                         str(outerRadius) + " MAP")

                        @retry(10)
                        def execFocal():
                            randomerror()
                            # Execute FocalStatistics
                            if not path.exists(focalRaster1):
                                arcpy.env.extent = cwdRaster1
                                outFocalStats = arcpy.sa.FocalStatistics(cwdRaster1,
                                                    InNeighborhood, "MINIMUM","DATA")
                                if setCoresToNull:                    
                                    outFocalStats2 = arcpy.sa.Con(outFocalStats > 0, outFocalStats) # Set areas overlapping cores to NoData xxx
                                    outFocalStats2.save(focalRaster1) #xxx
                                else:
                                    outFocalStats.save(focalRaster1) #xxx
                                arcpy.env.extent = cfg.RESRAST

                            if not path.exists(focalRaster2):
                                arcpy.env.extent = cwdRaster2
                                outFocalStats = arcpy.sa.FocalStatistics(cwdRaster2,
                                                InNeighborhood, "MINIMUM","DATA")
                                if setCoresToNull:                    
                                    outFocalStats2 = arcpy.sa.Con(outFocalStats > 0, outFocalStats) # Set areas overlapping cores to NoData xxx
                                    outFocalStats2.save(focalRaster2)#xxx
                                else:
                                    outFocalStats.save(focalRaster2) #xxx

                                arcpy.env.extent = cfg.RESRAST
                        execFocal()
                                                
                        lu.delete_data(cwdTemp1)
                        lu.delete_data(cwdTemp2)
                        
                        barrierRaster = path.join(cbarrierdir, "b" + str(radius)
                              + "_" + str(corex) + "_" +
                              str(corey)+'.tif') 
                             
                        if cfg.SUM_BARRIERS: # Need to set nulls to 0, also 
                                             # create trim rasters as we go

                            outRas = ((lcDist - Raster(focalRaster1) - 
                                      Raster(focalRaster2) - dia) / dia)
                            outCon = arcpy.sa.Con(IsNull(outRas),0,outRas)
                            outCon2 = arcpy.sa.Con(outCon<0,0,outCon)                            
                            outCon2.save(barrierRaster)
                            
                            # Execute FocalStatistics to fill out search radii                            
                            InNeighborhood = "CIRCLE " + str(outerRadius) + " MAP"
                            fillRaster = path.join(cbarrierdir, "b" + str(radius)
                            + "_" + str(corex) + "_" + str(corey) +"_fill.tif")
                            outFocalStats = arcpy.sa.FocalStatistics(barrierRaster,
                                                  InNeighborhood, "MAXIMUM","DATA")
                            outFocalStats.save(fillRaster)                            

                            if cfg.WRITE_TRIM_RASTERS:                            
                                trmRaster = path.join(cbarrierdir, "b" + 
                                                      str(radius)
                                + "_" + str(corex) + "_" + str(corey) +"_trim.tif")
                                rasterList = [fillRaster, resistFillRaster]
                                outCellStatistics = arcpy.sa.CellStatistics(
                                                            rasterList, "MINIMUM")
                                outCellStatistics.save(trmRaster)
                               
                        else:
                            #Calculate potential benefit per map unit restored
                            @retry(10)
                            def calcBen():
                                randomerror()
                                outRas = ((lcDist - Raster(focalRaster1)
                                      - Raster(focalRaster2) - dia) / dia)
                                outRas.save(barrierRaster)
                            calcBen()

                        if cfg.WRITE_PCT_RASTERS:
                            #Calculate PERCENT potential benefit per unit restored                        
                            barrierRasterPct = path.join(cbarrierdir, "b" + 
                                                    str(radius)
                                                    + "_" + str(corex) + "_" +
                                                    str(corey)+'_pct.tif') 
                            @retry(10)
                            def calcBenPct():                            
                                randomerror()
                                outras = (100 * (Raster(barrierRaster) / lcDist))
                                outras.save(barrierRasterPct)
                            calcBenPct()
                            
                        # Mosaic barrier results across core area pairs                    
                        mosaicDir = path.join(cfg.SCRATCHDIR,'mos'+str(radId)+'_'+str(x+1)) 
                        lu.create_dir(mosaicDir)
                        
                        mosFN = 'mos_temp'
                        tempMosaicRaster = path.join(mosaicDir,mosFN)
                        tempMosaicRasterTrim = path.join(mosaicDir,'mos_temp_trm')
                        arcpy.env.workspace = mosaicDir            
                        if linkLoop == 1:
                            #If this is the first grid then copy rather than mosaic
                            arcpy.CopyRaster_management(barrierRaster, 
                                                            tempMosaicRaster)
                            if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                                arcpy.CopyRaster_management(trmRaster, 
                                                            tempMosaicRasterTrim)                       
                            
                        else:                    
                            if cfg.SUM_BARRIERS:
                                outCon = arcpy.sa.Con(Raster (barrierRaster) < 0, lastMosaicRaster, 
                                        Raster(barrierRaster) + Raster(lastMosaicRaster))
                                outCon.save(tempMosaicRaster)                      
                                if cfg.WRITE_TRIM_RASTERS:
                                    outCon = arcpy.sa.Con(Raster
                                    (trmRaster) < 0, lastMosaicRasterTrim, 
                                    Raster(trmRaster) + Raster(
                                    lastMosaicRasterTrim))
                                    outCon.save(tempMosaicRasterTrim) 
                                
                            else:
                                rasterString = ('"'+barrierRaster+";" + 
                                                lastMosaicRaster+'"')
                                @retry(10)
                                def mosaicToNew():
                                    randomerror()
                                    arcpy.MosaicToNewRaster_management(
                                        rasterString,mosaicDir,mosFN, "", 
                                        "32_BIT_FLOAT", arcpy.env.cellSize, "1", 
                                        "MAXIMUM", "MATCH")
                                mosaicToNew()
                                # gprint(str(corex)+'0'+str(corey))
                                
                                
                        if linkLoop>1: #Clean up from previous loop
                            lu.delete_data(lastMosaicRaster)
                            lastMosaicDir =path.dirname(lastMosaicRaster) 
                            lu.clean_out_workspace(lastMosaicDir)
                            lu.delete_dir(lastMosaicDir)
                            
                        lastMosaicRaster = tempMosaicRaster
                        if cfg.WRITE_TRIM_RASTERS:
                            lastMosaicRasterTrim = tempMosaicRasterTrim             
                        if cfg.WRITE_PCT_RASTERS:
                            mosPctFN = 'mos_temp_pct'
                            mosaicDirPct = path.join(cfg.SCRATCHDIR,'mosP'+str(radId)+'_'+str(x+1)) 
                            lu.create_dir(mosaicDirPct)                            
                            tempMosaicRasterPct = path.join(mosaicDirPct,mosPctFN)
                            if linkLoop == 1:
                                # If this is the first grid then copy 
                                # rather than mosaic
                                if cfg.SUM_BARRIERS:
                                    outCon = arcpy.sa.Con(Raster(barrierRasterPct) 
                                        < 0, 0, arcpy.sa.Con(IsNull(
                                        barrierRasterPct), 0, barrierRasterPct)) 
                                    outCon.save(tempMosaicRasterPct)
                                else:
                                    arcpy.CopyRaster_management(barrierRasterPct, 
                                                             tempMosaicRasterPct)
                                                
                            else:                
                                if cfg.SUM_BARRIERS:
                                    @retry(10)
                                    def sumBarriers():
                                        randomerror()
                                        outCon = arcpy.sa.Con(Raster(barrierRasterPct) < 0, 
                                            lastMosaicRasterPct, Raster(barrierRasterPct) + Raster(
                                            lastMosaicRasterPct))
                                        outCon.save(tempMosaicRasterPct)
                                    sumBarriers()
                                else:
                                    rasterString = ('"' + barrierRasterPct + ";" + 
                                                    lastMosaicRasterPct + '"')
                                    @retry(10)
                                    def maxBarriers():
                                        randomerror()
                                        arcpy.MosaicToNewRaster_management(
                                            rasterString,mosaicDirPct,mosPctFN, "", 
                                            "32_BIT_FLOAT", arcpy.env.cellSize, "1", 
                                            "MAXIMUM", "MATCH")
                                    maxBarriers()
                                    
                            if linkLoop>1: #Clean up from previous loop
                                lu.delete_data(lastMosaicRasterPct)
                                lastMosaicDirPct =path.dirname(lastMosaicRasterPct) 
                                lu.clean_out_workspace(lastMosaicDirPct)
                                lu.delete_dir(lastMosaicDirPct)
                            
                            # lu.delete_data(lastMosaicRasterPct)
                            lastMosaicRasterPct = tempMosaicRasterPct                    
                        
                        if not cfg.SAVEBARRIERRASTERS:
                            lu.delete_data(barrierRaster)
                            if cfg.WRITE_PCT_RASTERS:
                                lu.delete_data(barrierRasterPct)
                            if cfg.WRITE_TRIM_RASTERS:                                                    
                                lu.delete_data(trmRaster)                            
                            
                            
                        # Temporarily disable links in linktable -
                        # don't want to mosaic them twice
                        for y in range (x+1,numLinks):
                            corex1 = int(coreList[y,0])
                            corey1 = int(coreList[y,1])
                            if corex1 == corex and corey1 == corey:
                                linkTable[y,cfg.LTB_LINKTYPE] = (
                                    linkTable[y,cfg.LTB_LINKTYPE] + 1000)
                            elif corex1==corey and corey1==corex:
                                linkTable[y,cfg.LTB_LINKTYPE] = (
                                    linkTable[y,cfg.LTB_LINKTYPE] + 1000)               

                if numCorridorLinks > 1 and pctDone < 100:
                    gprint('100 percent done')
                gprint('Summarizing barrier data for search radius.')
                #rows that were temporarily disabled
                rows = npy.where(linkTable[:,cfg.LTB_LINKTYPE]>1000)
                linkTable[rows,cfg.LTB_LINKTYPE] = (
                    linkTable[rows,cfg.LTB_LINKTYPE] - 1000)

                # -----------------------------------------------------------------
                
                # Set negative values to null or zero and write geodatabase. 
                mosaicFN = (PREFIX + "_BarrierCenters" + sumSuffix + "_Rad" + 
                           str(radius))
                mosaicRaster = path.join(cfg.BARRIERGDB, mosaicFN) 
                arcpy.env.extent = cfg.RESRAST
                
                # if setCoresToNull:                
                    # outCon = arcpy.sa.Con(Raster(tempMosaicRaster) < 0, 0, 
                                   # tempMosaicRaster) #xxx
                    # outCon.save(mosaicRaster) #xxx                            
                # else:
                outSetNull = arcpy.sa.SetNull(tempMosaicRaster, tempMosaicRaster,
                                              "VALUE < 0") #xxx orig
                outSetNull.save(mosaicRaster)
                
                lu.delete_data(tempMosaicRaster)
                
                if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    mosaicFN = (PREFIX + "_BarrierCircles_RBMin" + sumSuffix + 
                                "_Rad" + str(radius))
                    mosaicRasterTrim = path.join(cfg.BARRIERGDB, mosaicFN)
                    arcpy.CopyRaster_management(tempMosaicRasterTrim, 
                                                            mosaicRasterTrim)
                    lu.delete_data(tempMosaicRaster)
                            
                if cfg.WRITE_PCT_RASTERS:                        
                    # Do same for percent raster
                    mosaicPctFN = (PREFIX + "_BarrierCenters_Pct" + sumSuffix + 
                                   "_Rad" + str(radius))
                    arcpy.env.extent = cfg.RESRAST
                    outSetNull = arcpy.sa.SetNull(tempMosaicRasterPct, 
                                                  tempMosaicRasterPct, "VALUE < 0")
                    mosaicRasterPct = path.join(cfg.BARRIERGDB, mosaicPctFN)
                    outSetNull.save(mosaicRasterPct)
                    lu.delete_data(tempMosaicRasterPct)
                           
                
                # 'Grow out' maximum restoration gain to
                # neighborhood size for display
                InNeighborhood = "CIRCLE " + str(outerRadius) + " MAP"
                # Execute FocalStatistics
                fillRasterFN = "barriers_fill" + str(outerRadius) + tif
                fillRaster = path.join(cfg.BARRIERBASEDIR, fillRasterFN)
                outFocalStats = arcpy.sa.FocalStatistics(mosaicRaster,
                                                InNeighborhood, "MAXIMUM","DATA")
                outFocalStats.save(fillRaster)

                if cfg.WRITE_PCT_RASTERS:
                    # Do same for percent raster
                    fillRasterPctFN = "barriers_fill_pct" + str(outerRadius) + tif
                    fillRasterPct = path.join(cfg.BARRIERBASEDIR, fillRasterPctFN)
                    outFocalStats = arcpy.sa.FocalStatistics(mosaicRasterPct,
                                                InNeighborhood, "MAXIMUM","DATA")
                    outFocalStats.save(fillRasterPct)
                

                #Place copies of filled rasters in output geodatabase
                arcpy.env.workspace = cfg.BARRIERGDB
                fillRasterFN = (PREFIX + "_BarrrierCircles" + sumSuffix + "_Rad" + 
                                str(outerRadius))
                arcpy.CopyRaster_management(fillRaster, fillRasterFN) 
                if cfg.WRITE_PCT_RASTERS:
                    fillRasterPctFN = (PREFIX + "_BarrrierCircles_Pct" + sumSuffix + 
                                      "_Rad" + str(outerRadius))
                    arcpy.CopyRaster_management(fillRasterPct, fillRasterPctFN) 

                if not cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    # Create pared-down version of filled raster- remove pixels 
                    # that don't need restoring by allowing a pixel to only 
                    # contribute its resistance value to restoration gain
                    outRasterFN = "barriers_trm" + str(outerRadius) + tif
                    outRaster = path.join(cfg.BARRIERBASEDIR,outRasterFN)
                    rasterList = [fillRaster, resistFillRaster]
                    outCellStatistics = arcpy.sa.CellStatistics(rasterList, 
                                                                "MINIMUM")
                    outCellStatistics.save(outRaster)

                    #SECOND ROUND TO CLIP BY DATA VALUES IN BARRIER RASTER
                    outRaster2FN = ("barriers_trm"  + sumSuffix + str(outerRadius) 
                                   + "_2" + tif)
                    outRaster2 = path.join(cfg.BARRIERBASEDIR,outRaster2FN)
                    output = arcpy.sa.Con(IsNull(fillRaster),fillRaster,outRaster)
                    output.save(outRaster2)
                    outRasterFN = (PREFIX + "_BarrierCircles_RBMin"  + sumSuffix + 
                                  "_Rad" + str(outerRadius))

                    outRasterPath= path.join(cfg.BARRIERGDB, outRasterFN)
                    arcpy.CopyRaster_management(outRaster2, outRasterFN)
                randomerror()
                startTime=lu.elapsed_time(startTime)
Example #7
0
def STEP8_calc_pinchpoints():
    """ Maps pinch points in Linkage Mapper corridors using Circuitscape
        given CWD calculations from s3_calcCwds.py.

    """
    try:
        lu.dashline(0)
        gprint('Running script ' + _SCRIPT_NAME)

        restartFlag = False
        if cfg.CWDCUTOFF < 0:
            cfg.CWDCUTOFF = cfg.CWDCUTOFF * -1
            restartFlag = True  # Restart code in progress

        CSPATH = lu.get_cs_path()
        outputGDB = path.join(cfg.OUTPUTDIR, path.basename(cfg.PINCHGDB))

        arcpy.OverWriteOutput = True
        arcpy.env.workspace = cfg.SCRATCHDIR
        arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
        arcpy.env.pyramid = "NONE"
        arcpy.env.rasterstatistics = "NONE"

        # set the analysis extent and cell size to that of the resistance
        # surface
        arcpy.env.extent = cfg.RESRAST
        arcpy.env.cellSize = cfg.RESRAST
        arcpy.snapraster = cfg.RESRAST

        resRaster = cfg.RESRAST
        arcpy.env.extent = "MINOF"

        minObject = arcpy.GetRasterProperties_management(resRaster, "MINIMUM")
        rasterMin = float(str(minObject.getOutput(0)))
        if rasterMin <= 0:
            msg = (
                'Error: resistance raster cannot have 0 or negative values.')
            lu.raise_error(msg)

        if cfg.DO_ADJACENTPAIRS:
            prevLcpShapefile = lu.get_lcp_shapefile(None, thisStep=8)
            if not arcpy.Exists(prevLcpShapefile):
                msg = ('Cannot find an LCP shapefile from step 5.  Please '
                       'rerun that step and any previous ones if necessary.')
                lu.raise_error(msg)

            # Remove lcp shapefile
            lcpShapefile = path.join(cfg.DATAPASSDIR, "lcpLines_s8.shp")
            lu.delete_data(lcpShapefile)

        inLinkTableFile = lu.get_prev_step_link_table(step=8)
        linkTable = lu.load_link_table(inLinkTableFile)
        numLinks = linkTable.shape[0]
        numCorridorLinks = lu.report_links(linkTable)
        if numCorridorLinks == 0:
            lu.dashline(1)
            msg = ('\nThere are no linkages. Bailing.')
            lu.raise_error(msg)

        if linkTable.shape[1] < 16:  # If linktable has no entries from prior
            # centrality or pinchpint analyses
            extraCols = npy.zeros((numLinks, 6), dtype="float64")
            linkTable = linkTable[:, 0:10]
            linkTable = npy.append(linkTable, extraCols, axis=1)
            linkTable[:, cfg.LTB_LCPLEN] = -1
            linkTable[:, cfg.LTB_CWDEUCR] = -1
            linkTable[:, cfg.LTB_CWDPATHR] = -1
            linkTable[:, cfg.LTB_EFFRESIST] = -1
            linkTable[:, cfg.LTB_CWDTORR] = -1
            linkTable[:, cfg.LTB_CURRENT] = -1
            del extraCols

        # set up directories for circuit and circuit mosaic grids
        # Create output geodatabase
        if not arcpy.Exists(cfg.PINCHGDB):
            arcpy.CreateFileGDB_management(cfg.OUTPUTDIR,
                                           path.basename(cfg.PINCHGDB))

        mosaicRaster = path.join(cfg.CIRCUITBASEDIR, "current_mos" + tif)
        coresToProcess = npy.unique(linkTable[:,
                                              cfg.LTB_CORE1:cfg.LTB_CORE2 + 1])
        maxCoreNum = max(coresToProcess)
        del coresToProcess

        lu.dashline(0)
        coreList = linkTable[:, cfg.LTB_CORE1:cfg.LTB_CORE2 + 1]
        coreList = npy.sort(coreList)
        #gprint('There are ' + str(len(npy.unique(coreList))) ' core areas.')

        INCIRCUITDIR = cfg.CIRCUITBASEDIR
        OUTCIRCUITDIR = path.join(cfg.CIRCUITBASEDIR, cfg.CIRCUITOUTPUTDIR_NM)
        CONFIGDIR = path.join(INCIRCUITDIR, cfg.CIRCUITCONFIGDIR_NM)

        # Cutoff value text to append to filenames
        cutoffText = str(cfg.CWDCUTOFF)
        if cutoffText[-6:] == '000000':
            cutoffText = cutoffText[0:-6] + 'm'
        elif cutoffText[-3:] == '000':
            cutoffText = cutoffText[0:-3] + 'k'

        if cfg.SQUARERESISTANCES:
            # Square resistance values
            squaredRaster = path.join(cfg.SCRATCHDIR, 'res_sqr')
            arcpy.env.workspace = cfg.SCRATCHDIR
            arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
            outRas = Raster(resRaster) * Raster(resRaster)
            outRas.save(squaredRaster)
            resRaster = squaredRaster

        if cfg.DO_ADJACENTPAIRS:
            linkLoop = 0
            lu.dashline(1)
            gprint('Mapping pinch points in individual corridors \n'
                   'using Circuitscape.')
            lu.dashline(1)
            gprint('If you try to cancel your run and the Arc dialog hangs, ')
            gprint('you can kill Circuitscape by opening Windows Task Manager')
            gprint('and ending the cs_run.exe process.')
            lu.dashline(2)

            for x in range(0, numLinks):
                linkId = str(int(linkTable[x, cfg.LTB_LINKID]))
                if not (linkTable[x, cfg.LTB_LINKTYPE] > 0):
                    continue
                linkLoop = linkLoop + 1
                linkDir = path.join(cfg.SCRATCHDIR, 'link' + linkId)
                if restartFlag == True and path.exists(linkDir):
                    gprint('continuing')
                    continue
                restartFlag = False
                lu.create_dir(linkDir)
                start_time1 = time.clock()

                # source and target cores
                corex = int(coreList[x, 0])
                corey = int(coreList[x, 1])

                # Get cwd rasters for source and target cores
                cwdRaster1 = lu.get_cwd_path(corex)
                cwdRaster2 = lu.get_cwd_path(corey)

                lccNormRaster = path.join(linkDir, 'lcc_norm')
                arcpy.env.extent = "MINOF"

                link = lu.get_links_from_core_pairs(linkTable, corex, corey)
                lcDist = float(linkTable[link, cfg.LTB_CWDIST])

                # Normalized lcc rasters are created by adding cwd rasters
                # and subtracting the least cost distance between them.
                outRas = Raster(cwdRaster1) + Raster(cwdRaster2) - lcDist
                outRas.save(lccNormRaster)

                #create raster mask
                resMaskRaster = path.join(linkDir, 'res_mask' + tif)

                #create raster mask
                outCon = arcpy.sa.Con(
                    Raster(lccNormRaster) <= cfg.CWDCUTOFF, 1)
                outCon.save(resMaskRaster)

                # Convert to poly.  Use as mask to clip resistance raster.
                resMaskPoly = path.join(linkDir, 'res_mask_poly.shp')
                arcpy.RasterToPolygon_conversion(resMaskRaster, resMaskPoly,
                                                 "NO_SIMPLIFY")
                arcpy.env.extent = resMaskPoly

                # Includes 0 values in some cases with CP LI model if tif
                # so using ESRI Grid format
                resClipRasterMasked = path.join(linkDir, 'res_clip_m')
                # Extract masked resistance raster.
                # Needs to be float to get export to npy to work.
                outRas = arcpy.sa.ExtractByMask(resRaster, resMaskPoly) + 0.0
                outRas.save(resClipRasterMasked)

                resNpyFN = 'resistances_link_' + linkId + '.npy'
                resNpyFile = path.join(INCIRCUITDIR, resNpyFN)
                numElements, numResistanceNodes = export_ras_to_npy(
                    resClipRasterMasked, resNpyFile)

                totMem, availMem = lu.get_mem()
                # gprint('Total memory: str(totMem))
                if numResistanceNodes / availMem > 2000000:
                    lu.dashline(1)
                    lu.warn('Warning:')
                    lu.warn('Circuitscape can only solve 2-3 million nodes')
                    lu.warn(
                        'per gigabyte of available RAM. \nTotal physical RAM'
                        ' on your machine is ~' + str(totMem) +
                        ' GB. \nAvailable memory is ~' + str(availMem) +
                        ' GB. \nYour resistance raster has ' +
                        str(numResistanceNodes) + ' nodes.')
                    lu.dashline(2)
                corePairRaster = path.join(linkDir, 'core_pairs' + tif)
                arcpy.env.extent = resClipRasterMasked

                # Next result needs to be floating pt for numpy export
                outCon = arcpy.sa.Con(
                    Raster(cwdRaster1) == 0, corex,
                    arcpy.sa.Con(Raster(cwdRaster2) == 0, corey + 0.0))
                outCon.save(corePairRaster)

                coreNpyFN = 'cores_link_' + linkId + '.npy'
                coreNpyFile = path.join(INCIRCUITDIR, coreNpyFN)
                numElements, numNodes = export_ras_to_npy(
                    corePairRaster, coreNpyFile)

                arcpy.env.extent = "MINOF"

                # Set circuitscape options and call
                options = lu.setCircuitscapeOptions()
                if cfg.WRITE_VOLT_MAPS == True:
                    options['write_volt_maps'] = True
                options['habitat_file'] = resNpyFile

                # if int(linkId) > 2:
                # options['habitat_file'] = 'c:\\test.dummy'

                options['point_file'] = coreNpyFile
                options['set_focal_node_currents_to_zero'] = True
                outputFN = 'Circuitscape_link' + linkId + '.out'
                options['output_file'] = path.join(OUTCIRCUITDIR, outputFN)
                if numElements > 250000:
                    options['print_timings'] = True
                configFN = 'pinchpoint_config' + linkId + '.ini'

                outConfigFile = path.join(CONFIGDIR, configFN)
                lu.writeCircuitscapeConfigFile(outConfigFile, options)
                gprint('Processing link ID #' + str(linkId) +
                       '. Resistance map'
                       ' has ' + str(int(numResistanceNodes)) + ' nodes.')

                memFlag = call_circuitscape(CSPATH, outConfigFile)

                currentFN = ('Circuitscape_link' + linkId + '_cum_curmap.npy')
                currentMap = path.join(OUTCIRCUITDIR, currentFN)

                if not arcpy.Exists(currentMap):
                    print_failure(numResistanceNodes, memFlag, 10)
                    numElements, numNodes = export_ras_to_npy(
                        resClipRasterMasked, resNpyFile)
                    memFlag = call_circuitscape(CSPATH, outConfigFile)

                    currentFN = ('Circuitscape_link' + linkId +
                                 '_cum_curmap.npy')
                    currentMap = path.join(OUTCIRCUITDIR, currentFN)

                if not arcpy.Exists(currentMap):
                    msg = (
                        '\nCircuitscape failed. See error information above.')
                    arcpy.AddError(msg)
                    lu.write_log(msg)
                    exit(1)

                # Either set core areas to nodata in current map or
                # divide each by its radius
                currentRaster = path.join(linkDir, "current" + tif)
                import_npy_to_ras(currentMap, corePairRaster, currentRaster)

                if cfg.WRITE_VOLT_MAPS == True:
                    voltFN = ('Circuitscape_link' + linkId + '_voltmap_' +
                              str(corex) + '_' + str(corey) + '.npy')
                    voltMap = path.join(OUTCIRCUITDIR, voltFN)
                    voltRaster = path.join(
                        outputGDB, cfg.PREFIX + "_voltMap_" + str(corex) +
                        '_' + str(corey))
                    import_npy_to_ras(voltMap, corePairRaster, voltRaster)
                    gprint('Building output statistics and pyramids '
                           'for voltage raster\n')
                    lu.build_stats(voltRaster)

                arcpy.env.extent = currentRaster

                if SETCORESTONULL:
                    # Set core areas to NoData in current map for color ramping
                    currentRaster2 = currentRaster + '2' + tif
                    outCon = arcpy.sa.Con(
                        arcpy.sa.IsNull(Raster(corePairRaster)),
                        Raster(currentRaster))
                    outCon.save(currentRaster2)
                    currentRaster = currentRaster2
                arcpy.env.extent = "MAXOF"
                if linkLoop == 1:
                    lu.delete_data(mosaicRaster)

                    @retry(10)
                    def copyRas2():
                        arcpy.CopyRaster_management(currentRaster,
                                                    mosaicRaster)

                    copyRas2()
                else:

                    @retry(10)
                    def mosaicRas():
                        arcpy.Mosaic_management(currentRaster, mosaicRaster,
                                                "MAXIMUM", "MATCH")

                    mosaicRas()

                resistancesFN = ('Circuitscape_link' + linkId +
                                 '_resistances_3columns.out')

                resistancesFile = path.join(OUTCIRCUITDIR, resistancesFN)
                resistances = npy.loadtxt(resistancesFile,
                                          dtype='Float64',
                                          comments='#')

                resistance = float(str(arcpy.env.cellSize)) * resistances[2]
                linkTable[link, cfg.LTB_EFFRESIST] = resistance

                # Ratio
                if not cfg.SQUARERESISTANCES:
                    linkTable[link, cfg.LTB_CWDTORR] = (
                        linkTable[link, cfg.LTB_CWDIST] /
                        linkTable[link, cfg.LTB_EFFRESIST])
                # Clean up
                if cfg.SAVE_TEMP_CIRCUIT_FILES == False:
                    lu.delete_file(coreNpyFile)
                    coreNpyBase, extension = path.splitext(coreNpyFile)
                    lu.delete_data(coreNpyBase + '.hdr')
                    lu.delete_file(resNpyFile)
                    resNpyBase, extension = path.splitext(resNpyFile)
                    lu.delete_data(resNpyBase + '.hdr')
                    lu.delete_file(currentMap)
                    curMapBase, extension = path.splitext(currentMap)
                    lu.delete_data(curMapBase + '.hdr')
                    lu.delete_data(currentRaster)
                    lu.clean_out_workspace(linkDir)
                    lu.delete_dir(linkDir)
                gprint('Finished with link ID #' + str(linkId) + '. ' +
                       str(linkLoop) + ' out of ' + str(numCorridorLinks) +
                       ' links have been processed.')
                start_time1 = lu.elapsed_time(start_time1)

            outputRaster = path.join(
                outputGDB, cfg.PREFIX + "_current_adjacentPairs_" + cutoffText)
            lu.delete_data(outputRaster)

            @retry(10)
            def copyRas():
                arcpy.CopyRaster_management(mosaicRaster, outputRaster)

            copyRas()

            gprint('Building output statistics and pyramids '
                   'for corridor pinch point raster\n')
            lu.build_stats(outputRaster)

            finalLinkTable = lu.update_lcp_shapefile(linkTable,
                                                     lastStep=5,
                                                     thisStep=8)

            linkTableFile = path.join(cfg.DATAPASSDIR, "linkTable_s5_plus.csv")
            lu.write_link_table(finalLinkTable, linkTableFile, inLinkTableFile)
            linkTableFinalFile = path.join(
                cfg.OUTPUTDIR, cfg.PREFIX + "_linkTable_s5_plus.csv")
            lu.write_link_table(finalLinkTable, linkTableFinalFile,
                                inLinkTableFile)
            gprint('Copy of linkTable written to ' + linkTableFinalFile)
            #fixme: update sticks?

            gprint('Creating shapefiles with linework for links.')
            lu.write_link_maps(linkTableFinalFile, step=8)

            # Copy final link maps to gdb.
            lu.copy_final_link_maps(step=8)

            lu.delete_data(mosaicRaster)

        if not cfg.DO_ALLPAIRS:
            # Clean up temporary files
            if not cfg.SAVECURRENTMAPS:
                lu.delete_dir(OUTCIRCUITDIR)
            return

        lu.dashline(1)
        gprint('Mapping global pinch points among all\n'
               'core area pairs using Circuitscape.')

        if cfg.ALL_PAIR_SCENARIO == 'pairwise':
            gprint('Circuitscape will be run in PAIRWISE mode.')

        else:
            gprint('Circuitscape will be run in ALL-TO-ONE mode.')
        arcpy.env.workspace = cfg.SCRATCHDIR
        arcpy.env.scratchWorkspace = cfg.ARCSCRATCHDIR
        arcpy.env.extent = cfg.RESRAST
        arcpy.env.cellSize = cfg.RESRAST

        S8CORE_RAS = "s8core_ras"
        s8CoreRasPath = path.join(cfg.SCRATCHDIR, S8CORE_RAS)

        arcpy.FeatureToRaster_conversion(cfg.COREFC, cfg.COREFN, s8CoreRasPath,
                                         arcpy.env.cellSize)
        binaryCoreRaster = path.join(cfg.SCRATCHDIR, "core_ras_bin")

        # The following commands cause file lock problems on save.  using gp
        # instead.
        # outCon = arcpy.sa.Con(S8CORE_RAS, 1, "#", "VALUE > 0")
        # outCon.save(binaryCoreRaster)
        # gp.Con_sa(s8CoreRasPath, 1, binaryCoreRaster, "#", "VALUE > 0")
        outCon = arcpy.sa.Con(Raster(s8CoreRasPath) > 0, 1)
        outCon.save(binaryCoreRaster)
        s5corridorRas = path.join(cfg.OUTPUTGDB, cfg.PREFIX + "_corridors")

        if not arcpy.Exists(s5corridorRas):
            s5corridorRas = path.join(cfg.OUTPUTGDB,
                                      cfg.PREFIX + "_lcc_mosaic_int")

        outCon = arcpy.sa.Con(
            Raster(s5corridorRas) <= cfg.CWDCUTOFF, Raster(resRaster),
            arcpy.sa.Con(Raster(binaryCoreRaster) > 0, Raster(resRaster)))

        resRasClipPath = path.join(cfg.SCRATCHDIR, 'res_ras_clip')
        outCon.save(resRasClipPath)

        arcpy.env.cellSize = resRasClipPath
        arcpy.env.extent = resRasClipPath
        s8CoreRasClipped = s8CoreRasPath + '_c'

        # Produce core raster with same extent as clipped resistance raster
        # added to ensure correct data type- nodata values were positive for
        # cores otherwise
        outCon = arcpy.sa.Con(arcpy.sa.IsNull(Raster(s8CoreRasPath)), -9999,
                              Raster(s8CoreRasPath))
        outCon.save(s8CoreRasClipped)

        resNpyFN = 'resistances.npy'
        resNpyFile = path.join(INCIRCUITDIR, resNpyFN)
        numElements, numResistanceNodes = export_ras_to_npy(
            resRasClipPath, resNpyFile)

        totMem, availMem = lu.get_mem()
        # gprint('Total memory: str(totMem))
        if numResistanceNodes / availMem > 2000000:
            lu.dashline(1)
            lu.warn('Warning:')
            lu.warn('Circuitscape can only solve 2-3 million nodes')
            lu.warn('per gigabyte of available RAM. \nTotal physical RAM '
                    'on your machine is ~' + str(totMem) +
                    ' GB. \nAvailable memory is ~' + str(availMem) +
                    ' GB. \nYour resistance raster has ' +
                    str(numResistanceNodes) + ' nodes.')
            lu.dashline(0)

        coreNpyFN = 'cores.npy'
        coreNpyFile = path.join(INCIRCUITDIR, coreNpyFN)
        numElements, numNodes = export_ras_to_npy(s8CoreRasClipped,
                                                  coreNpyFile)

        arcpy.env.extent = "MINOF"

        options = lu.setCircuitscapeOptions()
        options['scenario'] = cfg.ALL_PAIR_SCENARIO
        options['habitat_file'] = resNpyFile
        options['point_file'] = coreNpyFile
        options['set_focal_node_currents_to_zero'] = True
        outputFN = 'Circuitscape.out'
        options['output_file'] = path.join(OUTCIRCUITDIR, outputFN)
        options['print_timings'] = True
        configFN = 'pinchpoint_allpair_config.ini'
        outConfigFile = path.join(CONFIGDIR, configFN)
        lu.writeCircuitscapeConfigFile(outConfigFile, options)
        gprint('\nResistance map has ' + str(int(numResistanceNodes)) +
               ' nodes.')
        lu.dashline(1)
        gprint('If you try to cancel your run and the Arc dialog hangs, ')
        gprint('you can kill Circuitscape by opening Windows Task Manager')
        gprint('and ending the cs_run.exe process.')
        lu.dashline(0)

        call_circuitscape(CSPATH, outConfigFile)
        # test = subprocess.call([CSPATH, outConfigFile],
        # creationflags = subprocess.CREATE_NEW_CONSOLE)

        if options['scenario'] == 'pairwise':
            rasterSuffix = "_current_allPairs_" + cutoffText

        else:
            rasterSuffix = "_current_allToOne_" + cutoffText

        currentFN = 'Circuitscape_cum_curmap.npy'
        currentMap = path.join(OUTCIRCUITDIR, currentFN)
        outputRaster = path.join(outputGDB, cfg.PREFIX + rasterSuffix)
        currentRaster = path.join(cfg.SCRATCHDIR, "current")

        try:
            import_npy_to_ras(currentMap, resRasClipPath, outputRaster)
        except:
            lu.dashline(1)
            msg = ('ERROR: Circuitscape failed. \n'
                   'Note: Circuitscape can only solve 2-3 million nodes'
                   '\nper gigabyte of available RAM. The resistance '
                   '\nraster for the last corridor had ' +
                   str(numResistanceNodes) + ' nodes.\n\nResistance '
                   'raster values that vary by >6 orders of \nmagnitude'
                   ' can also cause failures, as can a mismatch in '
                   '\ncore area and resistance raster extents.')
            arcpy.AddError(msg)
            lu.write_log(msg)
            exit(1)

        #set core areas to nodata
        if SETCORESTONULL:
            # Set core areas to NoData in current map for color ramping
            outputRasterND = outputRaster + '_noDataCores'
            outCon = arcpy.sa.SetNull(
                Raster(s8CoreRasClipped) > 0, Raster(outputRaster))
            outCon.save(outputRasterND)

        gprint('\nBuilding output statistics and pyramids '
               'for centrality raster.')
        lu.build_stats(outputRaster)
        lu.build_stats(outputRasterND)

        # Clean up temporary files
        if not cfg.SAVECURRENTMAPS:
            lu.delete_dir(OUTCIRCUITDIR)

    # Return GEOPROCESSING specific errors
    except arcpy.ExecuteError:
        lu.dashline(1)
        gprint('****Failed in step 8. Details follow.****')
        lu.exit_with_geoproc_error(_SCRIPT_NAME)

    # Return any PYTHON or system specific errors
    except:
        lu.dashline(1)
        gprint('****Failed in step 8. Details follow.****')
        lu.exit_with_python_error(_SCRIPT_NAME)
def circuitscape_master(argv=None):
    """

    """
    gprint = lu.gprint

    if argv is None:
        argv = sys.argv

    argv.append(get_cs_path())  # Add Circuitscape path

    cfg.configure(cfg.TOOL_CS, argv)

    try:
        lu.create_dir(cfg.LOGDIR)
        lu.create_dir(cfg.MESSAGEDIR)
        cfg.logFilePath = lu.create_log_file(cfg.PARAM_NAMES, argv)
        if cfg.DOPINCH :
            lu.log_metadata(cfg.COREFC, [cfg.RESRAST_IN])
        else:
            lu.log_metadata(cfg.COREFC)

        if cfg.CSPATH is None:
            lu.raise_error("Cannot find an installation of Circuitscape"
                           "\nin your Program Files directory.")

        lu.print_drive_warning()
        # Check core ID field.
        lu.check_cores(cfg.COREFC, cfg.COREFN)

        arcpy.env.outputCoordinateSystem = arcpy.Describe(cfg.COREFC).SpatialReference
        # Set data frame spatial reference to coordinate system of input data
        lu.set_dataframe_sr()

        arcpy.env.pyramid = "NONE"
        arcpy.env.rasterStatistics = "NONE"

        # Move adj and cwd results from earlier versions to datapass directory
        lu.move_old_results()

        if cfg.CWDCUTOFF > 0:
            lu.delete_dir(cfg.SCRATCHDIR)

        # restart code- in progress
        if cfg.CWDCUTOFF < 0:
            cfg.CWDCUTOFF = cfg.CWDCUTOFF * -1

        if not cfg.DOPINCH and not cfg.DOCENTRALITY:
            msg = ('ERROR: Please choose at least one option: pinch point or\n'
                    'network centrality analysis.')
            lu.raise_error(msg)

        lu.create_dir(cfg.SCRATCHDIR)
        lu.create_dir(cfg.ARCSCRATCHDIR)

        if cfg.DO_ALLPAIRS:
            #  Fixme: move raster path to config
            S5CORRIDORRAS = path.join(cfg.OUTPUTGDB,cfg.PREFIX + "_corridors")
            if not arcpy.Exists(S5CORRIDORRAS):
                S5CORRIDORRAS = path.join(cfg.OUTPUTGDB, cfg.PREFIX +
                                         "_lcc_mosaic_int")
            if not arcpy.Exists(S5CORRIDORRAS):
                msg = ('ERROR: Corridor raster created in step 5 is required'
                        '\nfor all-pair analyses, but was not found.')
                lu.raise_error(msg)
        if cfg.DOPINCH:
            if cfg.CWDCUTOFF == '#' or cfg.CWDCUTOFF == 0:
                msg = ('ERROR: CWD cutoff distance is required for pinch point'
                        ' analyses.')
                lu.raise_error(msg)

            # Make a local grid copy of resistance raster-
            # will run faster than gdb.
            lu.delete_data(cfg.RESRAST)
            if not arcpy.Exists(cfg.RESRAST_IN):
                msg = ('ERROR: Resistance raster is required for pinch point'
                        ' analyses, but was not found.')
                lu.raise_error(msg)

            arcpy.env.extent = cfg.RESRAST_IN
            desc = arcpy.Describe(cfg.RESRAST_IN)
            if hasattr(desc, "catalogPath"):
                cfg.RESRAST_IN = arcpy.Describe(cfg.RESRAST_IN).catalogPath

            gprint('\nMaking local copy of resistance raster.')
            try:
                arcpy.CopyRaster_management(cfg.RESRAST_IN, cfg.RESRAST)
            except Exception:
                msg = ('ERROR: Could not make a copy of your resistance raster. ' +
                    'Try re-starting ArcMap to release the file lock.')
                lu.raise_error(msg)

            arcpy.env.snapRaster = cfg.RESRAST

        if cfg.DOCENTRALITY:
            gprint("Creating output folder: " + cfg.CENTRALITYBASEDIR)
            if path.exists(cfg.CENTRALITYBASEDIR):
                shutil.rmtree(cfg.CENTRALITYBASEDIR)
            lu.create_dir(cfg.CENTRALITYBASEDIR)
            arcpy.CreateFolder_management(cfg.CENTRALITYBASEDIR,
                                        cfg.CIRCUITOUTPUTDIR_NM)
            arcpy.CreateFolder_management(cfg.CENTRALITYBASEDIR,
                                        cfg.CIRCUITCONFIGDIR_NM)
            lu.clean_out_workspace(cfg.CORECENTRALITYGDB)

            s7.STEP7_calc_centrality()
            if not cfg.SAVECENTRALITYDIR:
                lu.delete_dir(cfg.CENTRALITYBASEDIR)

        if cfg.DOPINCH:
            if cfg.CWDCUTOFF > 0: # Negative values mean we're restarting
                gprint("Creating output folder: " + cfg.CIRCUITBASEDIR)
                lu.delete_dir(cfg.CIRCUITBASEDIR)
                lu.create_dir(cfg.CIRCUITBASEDIR)
                arcpy.CreateFolder_management(cfg.CIRCUITBASEDIR,
                                        cfg.CIRCUITOUTPUTDIR_NM)
                arcpy.CreateFolder_management(cfg.CIRCUITBASEDIR,
                                        cfg.CIRCUITCONFIGDIR_NM)

            s8.STEP8_calc_pinchpoints()

            if not cfg.SAVE_TEMP_CIRCUIT_FILES:
                lu.delete_dir(cfg.SCRATCHDIR)
            if not cfg.SAVECIRCUITDIR:
                lu.delete_dir(cfg.CIRCUITBASEDIR)

        gprint('\nDONE!\n')

    # Return GEOPROCESSING specific errors
    except arcpy.ExecuteError:
        lu.exit_with_geoproc_error(_SCRIPT_NAME)

    # Return any PYTHON or system specific errors
    except Exception:
        lu.exit_with_python_error(_SCRIPT_NAME)
Example #9
0
            def do_radius_loop():
                """Do radius loop."""
                link_table = link_table_tmp.copy()
                start_time = time.clock()
                link_loop = 0
                pct_done = 0
                gprint('\nMapping barriers at a radius of ' + str(radius) +
                       ' ' + str(map_units))
                if cfg.SUM_BARRIERS:
                    gprint('using SUM method')
                else:
                    gprint('using MAXIMUM method')
                if num_corridor_links > 1:
                    gprint('0 percent done')
                last_mosaic_ras = None
                last_mosaic_ras_pct = None
                for x in range(0, num_links):
                    pct_done = lu.report_pct_done(
                        link_loop, num_corridor_links, pct_done)
                    if ((link_table[x, cfg.LTB_LINKTYPE] > 0) and
                            (link_table[x, cfg.LTB_LINKTYPE] < 1000)):
                        link_loop = link_loop + 1
                        # source and target cores
                        corex = int(core_list[x, 0])
                        corey = int(core_list[x, 1])

                        # Get cwd rasters for source and target cores
                        cwd_ras1 = lu.get_cwd_path(corex)
                        cwd_ras2 = lu.get_cwd_path(corey)

                        # Mask out areas above CWD threshold
                        cwd_tmp1 = None
                        cwd_tmp2 = None
                        if cfg.BARRIER_CWD_THRESH is not None:
                            if x == 1:
                                lu.dashline(1)
                                gprint('  Using CWD threshold of '
                                       + str(cfg.BARRIER_CWD_THRESH)
                                       + ' map units.')
                            arcpy.env.extent = cfg.RESRAST
                            arcpy.env.cellSize = cfg.RESRAST
                            arcpy.env.snapRaster = cfg.RESRAST
                            cwd_tmp1 = path.join(cfg.SCRATCHDIR,
                                                 "tmp" + str(corex))
                            out_con = arcpy.sa.Con(
                                cwd_ras1 < float(cfg.BARRIER_CWD_THRESH),
                                cwd_ras1)
                            out_con.save(cwd_tmp1)
                            cwd_ras1 = cwd_tmp1
                            cwd_tmp2 = path.join(cfg.SCRATCHDIR,
                                                 "tmp" + str(corey))
                            out_con = arcpy.sa.Con(
                                cwd_ras2 < float(cfg.BARRIER_CWD_THRESH),
                                cwd_ras2)
                            out_con.save(cwd_tmp2)
                            cwd_ras2 = cwd_tmp2

                        focal_ras1 = lu.get_focal_path(corex, radius)
                        focal_ras2 = lu.get_focal_path(corey, radius)

                        link = lu.get_links_from_core_pairs(link_table,
                                                            corex, corey)
                        lc_dist = float(link_table[link, cfg.LTB_CWDIST])

                        # Detect barriers at radius using neighborhood stats
                        # Create the Neighborhood Object
                        inner_radius = radius - 1
                        outer_radius = radius

                        dia = 2 * radius
                        in_neighborhood = ("ANNULUS " + str(inner_radius)
                                           + " " + str(outer_radius) + " MAP")

                        @Retry(10)
                        def exec_focal():
                            """Execute focal statistics."""
                            if not path.exists(focal_ras1):
                                arcpy.env.extent = cwd_ras1
                                out_focal_stats = arcpy.sa.FocalStatistics(
                                    cwd_ras1, in_neighborhood,
                                    "MINIMUM", "DATA")
                                if SET_CORES_TO_NULL:
                                    # Set areas overlapping cores to NoData xxx
                                    out_focal_stats2 = arcpy.sa.Con(
                                        out_focal_stats > 0, out_focal_stats)
                                    out_focal_stats2.save(focal_ras1)
                                else:
                                    out_focal_stats.save(focal_ras1)
                                arcpy.env.extent = cfg.RESRAST

                            if not path.exists(focal_ras2):
                                arcpy.env.extent = cwd_ras2
                                out_focal_stats = arcpy.sa.FocalStatistics(
                                    cwd_ras2, in_neighborhood,
                                    "MINIMUM", "DATA")
                                if SET_CORES_TO_NULL:
                                    # Set areas overlapping cores to NoData xxx
                                    out_focal_stats2 = arcpy.sa.Con(
                                        out_focal_stats > 0, out_focal_stats)
                                    out_focal_stats2.save(focal_ras2)
                                else:
                                    out_focal_stats.save(focal_ras2)
                                arcpy.env.extent = cfg.RESRAST
                        exec_focal()

                        lu.delete_data(cwd_tmp1)
                        lu.delete_data(cwd_tmp2)

                        barrier_ras = path.join(
                            cbarrierdir, "b" + str(radius) + "_" + str(corex)
                            + "_" + str(corey)+'.tif')

                        # Need to set nulls to 0,
                        # also create trim rasters as we go
                        if cfg.SUM_BARRIERS:
                            out_ras = ((lc_dist - arcpy.sa.Raster(focal_ras1) -
                                        arcpy.sa.Raster(focal_ras2) - dia)
                                       / dia)
                            out_con = arcpy.sa.Con(arcpy.sa.IsNull(out_ras),
                                                   0, out_ras)
                            out_con2 = arcpy.sa.Con(out_con < 0, 0, out_con)
                            out_con2.save(barrier_ras)

                            # Execute FocalStatistics to fill out search radii
                            in_neighborhood = ("CIRCLE " + str(outer_radius)
                                               + " MAP")
                            fill_ras = path.join(
                                cbarrierdir, "b" + str(radius) + "_"
                                + str(corex) + "_" + str(corey) + "_fill.tif")
                            out_focal_stats = arcpy.sa.FocalStatistics(
                                barrier_ras, in_neighborhood,
                                "MAXIMUM", "DATA")
                            out_focal_stats.save(fill_ras)

                            if cfg.WRITE_TRIM_RASTERS:
                                trm_ras = path.join(
                                    cbarrierdir, "b" + str(radius) + "_"
                                    + str(corex) + "_" + str(corey)
                                    + "_trim.tif")
                                ras_list = [fill_ras, resist_fill_ras]
                                out_cell_statistics = arcpy.sa.CellStatistics(
                                    ras_list, "MINIMUM")
                                out_cell_statistics.save(trm_ras)

                        else:

                            @Retry(10)
                            def clac_ben():
                                """Calculate potential benefit.

                                Calculate potential benefit per map unit
                                restored.
                                """
                                out_ras = (
                                    (lc_dist - arcpy.sa.Raster(focal_ras1)
                                     - arcpy.sa.Raster(focal_ras2) - dia)
                                    / dia)
                                out_ras.save(barrier_ras)
                            clac_ben()

                        if cfg.WRITE_PCT_RASTERS:
                            # Calculate % potential benefit per unit restored
                            barrier_ras_pct = path.join(
                                cbarrierdir, "b" + str(radius) + "_"
                                + str(corex) + "_" + str(corey)
                                + '_pct.tif')

                            @Retry(10)
                            def calc_ben_pct():
                                """Calc benefit percentage."""
                                outras = (100 * (arcpy.sa.Raster(barrier_ras)
                                                 / lc_dist))
                                outras.save(barrier_ras_pct)
                            calc_ben_pct()

                        # Mosaic barrier results across core area pairs
                        mosaic_dir = path.join(cfg.SCRATCHDIR, 'mos'
                                               + str(rad_id) + '_'
                                               + str(x + 1))
                        lu.create_dir(mosaic_dir)

                        mos_fn = 'mos_temp'
                        tmp_mosaic_ras = path.join(mosaic_dir, mos_fn)
                        tmp_mosaic_ras_trim = path.join(mosaic_dir,
                                                        'mos_temp_trm')
                        arcpy.env.workspace = mosaic_dir
                        if link_loop == 1:
                            last_mosaic_ras_trim = None
                            # For first grid copy rather than mosaic
                            arcpy.CopyRaster_management(barrier_ras,
                                                        tmp_mosaic_ras)
                            if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                                arcpy.CopyRaster_management(
                                    trm_ras, tmp_mosaic_ras_trim)
                        else:
                            if cfg.SUM_BARRIERS:
                                out_con = arcpy.sa.Con(
                                    arcpy.sa.Raster(barrier_ras) < 0,
                                    last_mosaic_ras,
                                    arcpy.sa.Raster(barrier_ras)
                                    + arcpy.sa.Raster(last_mosaic_ras))
                                out_con.save(tmp_mosaic_ras)
                                if cfg.WRITE_TRIM_RASTERS:
                                    out_con = arcpy.sa.Con(
                                        arcpy.sa.Raster(trm_ras) < 0,
                                        last_mosaic_ras_trim,
                                        arcpy.sa.Raster(trm_ras)
                                        + arcpy.sa.Raster(last_mosaic_ras_trim)
                                        )
                                    out_con.save(tmp_mosaic_ras_trim)

                            else:
                                in_rasters = (";".join([barrier_ras,
                                                        last_mosaic_ras]))

                                @Retry(10)
                                def mosaic_to_new():
                                    """Mosaic to new raster."""
                                    arcpy.MosaicToNewRaster_management(
                                        input_rasters=in_rasters,
                                        output_location=mosaic_dir,
                                        raster_dataset_name_with_extension\
                                        =mos_fn,
                                        pixel_type="32_BIT_FLOAT",
                                        cellsize=arcpy.env.cellSize,
                                        number_of_bands="1",
                                        mosaic_method="MAXIMUM")
                                mosaic_to_new()

                        if link_loop > 1:  # Clean up from previous loop
                            lu.delete_data(last_mosaic_ras)
                            last_mosaic_dir = path.dirname(last_mosaic_ras)
                            lu.clean_out_workspace(last_mosaic_dir)
                            lu.delete_dir(last_mosaic_dir)

                        last_mosaic_ras = tmp_mosaic_ras
                        if cfg.WRITE_TRIM_RASTERS:
                            last_mosaic_ras_trim = tmp_mosaic_ras_trim
                        if cfg.WRITE_PCT_RASTERS:
                            mos_pct_fn = 'mos_temp_pct'
                            mosaic_dir_pct = path.join(cfg.SCRATCHDIR, 'mosP'
                                                       + str(rad_id) + '_'
                                                       + str(x+1))
                            lu.create_dir(mosaic_dir_pct)
                            tmp_mosaic_ras_pct = path.join(mosaic_dir_pct,
                                                           mos_pct_fn)
                            if link_loop == 1:
                                # If this is the first grid then copy
                                # rather than mosaic
                                if cfg.SUM_BARRIERS:
                                    out_con = arcpy.sa.Con(
                                        arcpy.sa.Raster(barrier_ras_pct)
                                        < 0, 0,
                                        arcpy.sa.Con(arcpy.sa.IsNull
                                                     (barrier_ras_pct),
                                                     0, barrier_ras_pct))
                                    out_con.save(tmp_mosaic_ras_pct)
                                else:
                                    arcpy.CopyRaster_management(
                                        barrier_ras_pct, tmp_mosaic_ras_pct)

                            else:
                                if cfg.SUM_BARRIERS:

                                    @Retry(10)
                                    def sum_barriers():
                                        """Sum barriers."""
                                        out_con = arcpy.sa.Con(
                                            arcpy.sa.Raster(barrier_ras_pct)
                                            < 0,
                                            last_mosaic_ras_pct,
                                            arcpy.sa.Raster(barrier_ras_pct)
                                            + arcpy.sa.Raster(
                                                last_mosaic_ras_pct))
                                        out_con.save(tmp_mosaic_ras_pct)
                                    sum_barriers()
                                else:
                                    in_rasters = (";".join([barrier_ras_pct,
                                                  last_mosaic_ras_pct]))

                                    @Retry(10)
                                    def max_barriers():
                                        """Get max barriers."""
                                        arcpy.MosaicToNewRaster_management(
                                            input_rasters=in_rasters,
                                            output_location=mosaic_dir_pct,
                                            raster_dataset_name_with_extension
                                            =mos_pct_fn,
                                            pixel_type="32_BIT_FLOAT",
                                            cellsize=arcpy.env.cellSize,
                                            number_of_bands="1",
                                            mosaic_method="MAXIMUM")
                                    max_barriers()

                            if link_loop > 1:  # Clean up from previous loop
                                lu.delete_data(last_mosaic_ras_pct)
                                last_mosaic_dir_pct = path.dirname(
                                    last_mosaic_ras_pct)
                                lu.clean_out_workspace(last_mosaic_dir_pct)
                                lu.delete_dir(last_mosaic_dir_pct)

                            last_mosaic_ras_pct = tmp_mosaic_ras_pct

                        if not cfg.SAVEBARRIERRASTERS:
                            lu.delete_data(barrier_ras)
                            if cfg.WRITE_PCT_RASTERS:
                                lu.delete_data(barrier_ras_pct)
                            if cfg.WRITE_TRIM_RASTERS:
                                lu.delete_data(trm_ras)

                        # Temporarily disable links in linktable -
                        # don't want to mosaic them twice
                        for y in range(x + 1, num_links):
                            corex1 = int(core_list[y, 0])
                            corey1 = int(core_list[y, 1])
                            if corex1 == corex and corey1 == corey:
                                link_table[y, cfg.LTB_LINKTYPE] = (
                                    link_table[y, cfg.LTB_LINKTYPE] + 1000)
                            elif corex1 == corey and corey1 == corex:
                                link_table[y, cfg.LTB_LINKTYPE] = (
                                    link_table[y, cfg.LTB_LINKTYPE] + 1000)

                if num_corridor_links > 1 and pct_done < 100:
                    gprint('100 percent done')
                gprint('Summarizing barrier data for search radius.')
                # Rows that were temporarily disabled
                rows = npy.where(link_table[:, cfg.LTB_LINKTYPE] > 1000)
                link_table[rows, cfg.LTB_LINKTYPE] = (
                    link_table[rows, cfg.LTB_LINKTYPE] - 1000)
                # -----------------------------------------------------------------
                # Set negative values to null or zero and write geodatabase.
                mosaic_fn = (prefix + "_BarrierCenters" + sum_suffix + "_Rad" +
                             str(radius))
                mosaic_ras = path.join(cfg.BARRIERGDB, mosaic_fn)
                arcpy.env.extent = cfg.RESRAST

                out_set_null = arcpy.sa.SetNull(tmp_mosaic_ras,
                                                tmp_mosaic_ras,
                                                "VALUE < 0")  # xxx orig
                out_set_null.save(mosaic_ras)

                lu.delete_data(tmp_mosaic_ras)

                if cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    mosaic_fn = (prefix + "_BarrierCircles_RBMin" + sum_suffix
                                 + "_Rad" + str(radius))
                    mosaic_ras_trim = path.join(cfg.BARRIERGDB, mosaic_fn)
                    arcpy.CopyRaster_management(tmp_mosaic_ras_trim,
                                                mosaic_ras_trim)
                    lu.delete_data(tmp_mosaic_ras)

                if cfg.WRITE_PCT_RASTERS:
                    # Do same for percent raster
                    mosaic_pct_fn = (prefix + "_BarrierCenters_Pct"
                                     + sum_suffix + "_Rad" + str(radius))
                    arcpy.env.extent = cfg.RESRAST
                    out_set_null = arcpy.sa.SetNull(tmp_mosaic_ras_pct,
                                                    tmp_mosaic_ras_pct,
                                                    "VALUE < 0")
                    mosaic_ras_pct = path.join(cfg.BARRIERGDB, mosaic_pct_fn)
                    out_set_null.save(mosaic_ras_pct)
                    lu.delete_data(tmp_mosaic_ras_pct)

                # 'Grow out' maximum restoration gain to
                # neighborhood size for display
                in_neighborhood = "CIRCLE " + str(outer_radius) + " MAP"
                # Execute FocalStatistics
                fill_ras_fn = "barriers_fill" + str(outer_radius) + TIF
                fill_ras = path.join(cfg.BARRIERBASEDIR, fill_ras_fn)
                out_focal_stats = arcpy.sa.FocalStatistics(
                    mosaic_ras, in_neighborhood, "MAXIMUM", "DATA")
                out_focal_stats.save(fill_ras)

                if cfg.WRITE_PCT_RASTERS:
                    # Do same for percent raster
                    fill_ras_pct_fn = (
                        "barriers_fill_pct" + str(outer_radius) + TIF)
                    fill_ras_pct = path.join(cfg.BARRIERBASEDIR,
                                             fill_ras_pct_fn)
                    out_focal_stats = arcpy.sa.FocalStatistics(
                        mosaic_ras_pct, in_neighborhood, "MAXIMUM", "DATA")
                    out_focal_stats.save(fill_ras_pct)

                # Place copies of filled rasters in output geodatabase
                arcpy.env.workspace = cfg.BARRIERGDB
                fill_ras_fn = (prefix + "_BarrrierCircles" + sum_suffix
                               + "_Rad" + str(outer_radius))
                arcpy.CopyRaster_management(fill_ras, fill_ras_fn)
                if cfg.WRITE_PCT_RASTERS:
                    fill_ras_pct_fn = (prefix + "_BarrrierCircles_Pct"
                                       + sum_suffix + "_Rad"
                                       + str(outer_radius))
                    arcpy.CopyRaster_management(fill_ras_pct,
                                                fill_ras_pct_fn)

                if not cfg.SUM_BARRIERS and cfg.WRITE_TRIM_RASTERS:
                    # Create pared-down version of filled raster- remove pixels
                    # that don't need restoring by allowing a pixel to only
                    # contribute its resistance value to restoration gain
                    out_ras_fn = "barriers_trm" + str(outer_radius) + TIF
                    out_ras = path.join(cfg.BARRIERBASEDIR, out_ras_fn)
                    ras_list = [fill_ras, resist_fill_ras]
                    out_cell_statistics = arcpy.sa.CellStatistics(ras_list,
                                                                  "MINIMUM")
                    out_cell_statistics.save(out_ras)

                    # SECOND ROUND TO CLIP BY DATA VALUES IN BARRIER RASTER
                    out_ras_2fn = ("barriers_trm" + sum_suffix
                                   + str(outer_radius) + "_2" + TIF)
                    out_ras2 = path.join(cfg.BARRIERBASEDIR, out_ras_2fn)
                    output = arcpy.sa.Con(arcpy.sa.IsNull(fill_ras),
                                          fill_ras, out_ras)
                    output.save(out_ras2)
                    out_ras_fn = (prefix + "_BarrierCircles_RBMin"
                                  + sum_suffix + "_Rad"
                                  + str(outer_radius))
                    arcpy.CopyRaster_management(out_ras2, out_ras_fn)
                start_time = lu.elapsed_time(start_time)