Question

I have written a script that uses pool.map to process multiple netCDF files and store information in a table. Each process runs a function to process one year. Each year has it's own individual file geodatabase, table within that geodatabase, and mxd. I also set the default workspace and scratch workspace to that geodatabase. For example when the function loads the year 1979 it accesses the 1979 geodatabase, 1979 table within that geodatabase, and 1979 mxd. 1980 would access the 1980 geodatabase, 1970 table within that geodatabase, and 1980 mxd.

If I run 1 process everything works fine. If I try to run 2 or more I get Fatal Error (INFADI) Missing Directory. Right now I'm running 6 processes. 4 Crash and the other 2 keep going without a problem.

Here is the code:

# Multiprocessing netCDF data into a table
######################################

import arcpy, calendar, datetime, numpy, multiprocessing, sys, re, timeit, os
from arcpy.sa import *

#Receive day and year and return the date str in MM/DD/YYYY
def getDate(day, year):
        date = datetime.datetime(year, 1, 1) + datetime.timedelta(day)
        date = date.timetuple()
        date = str(date[1]) + '/' + str(date[2]) + '/' + str(date[0])
        return date


#Main loop
#Receive a year int and process all dates within "good" months
def doCalc(year):
        yearstr = str(year)
        print('Starting doCalc: ' + yearstr)

        ############################################
        #### CHANGE THIS INPUT ####
        Species = 'Mallard'
        Regiondb = 'North_America' #Spaces not allowed in filename to map
        Region = 'Duck Zone' #Spaces allowed in DB
        regionField = 'ZONE_NAME'
        ############################################

        defaultGDB = "D:\\GIS\projects\\LCC_WSI_Climate\\year" + yearstr + ".gdb"
        #Setting environmental variables
        arcpy.env.workspace = defaultGDB
        arcpy.env.scratchWorkspace = defaultGDB
        arcpy.env.overwriteOutput = True

        #desired months
        goodmonth = (1, 2, 3, 9, 10, 11, 12)

        #Acquire necessary extension and exit if it can't acquire
        #Spatial Extension
        try:
                if arcpy.CheckExtension("Spatial") == "Available":
                        arcpy.CheckOutExtension("Spatial")
                        print("Acquired Spatial license")
                else:
                        sys.exit("No Spatial Analyst license available")
        except:
                sys.exit("No Spatial Analyst license available")

        #Geostats Extension
        try:
                if arcpy.CheckExtension("GeoStats") == "Available":
                        arcpy.CheckOutExtension("GeoStats")
                        print("Acquired GeoStats license")
                else:
                        sys.exit("No GeoStats license available")
        except:
                sys.exit("No GeoStats license available")

        #Try and except statements currently used for debugging and that is why the exceps are not specific.     
        try:
                #Select map document and set up layers.  Using a map document because NetCDFRasters aren't
                #playing nice if not "living" in a document
                print('Starting :' + yearstr)
                start = timeit.default_timer()
                mxd = arcpy.mapping.MapDocument("D:/GIS/projects/LCC_WSI_Climate/python code/WSI_maps"+yearstr+".mxd")
                df = arcpy.mapping.ListDataFrames(mxd)[0]

                #Set the table to write to according to the year received
                for table in arcpy.mapping.ListTableViews(mxd):
                        if table.name == 'T'+yearstr:
                                WSITable = table
                #Set the Clip layer according to the Region specified above
                for dflayer in arcpy.mapping.ListLayers(mxd,"", df):
                        if dflayer.name == Region:
                                WSIClip = dflayer
                        if dflayer.name == 'wsi_Layer':
                                WSILayer = dflayer

                #Set directory where netCDF files reside                
                direct = "D:/GIS/projects/LCC_WSI_Climate/python code/wsi/"
                #Set netCDF file according to year received
                inputLayer = direct +'wsi.' + yearstr + '.nc'

                #If it's 1979 it starts in September.
                if year == 1979:
                        startday = 243
                else:
                        startday = 0

                #Make sure the wsi_Layer is the correct file.
                arcpy.MakeNetCDFRasterLayer_md(inputLayer, "wsi", "x", "y", "wsi_Layer")                      

                #Checks if the current year is a leap year
                if calendar.isleap(year):
                        maxday = 366
                else:
                        maxday = 365

                #Cycle through every day within the year
                for daycnt in range(startday, maxday):
                        day = 0
                        sendday = daycnt+1
                        date = getDate(daycnt, year)
                        newdate = datetime.datetime(year, 1, 1) + datetime.timedelta(daycnt)
                        newdate = newdate.timetuple()
                        month = newdate[1]
                        day = newdate[2]

                        #If the month is not desired it will skip the day and continue with the next day
                        if month not in goodmonth:
                                continue

                        datestr = str(month) + '/' + str(day) + '/' + str(year)
                        print(datestr)

                        #Use the Select by Dimension tool to change the netCDF layer to the current date
                        WSILayerRas = Raster("wsi_Layer")
                        arcpy.SelectByDimension_md(WSILayerRas, [["time", date]],"BY_VALUE")
                        #Save the file in defaultGDB.  Processing didn't work without saving.
                        WSILayerRas.save("Temp"+yearstr)

                        ##########################################
                        ## Regions
                        ##
                        wsikm = 0
                        datalist = []
                        #Calculate time
                        time = 'time ' + str(date)      


                        #Setup the cursor to write to the output Table defined above (taken from mxd).
                        cursorout = arcpy.da.InsertCursor(WSITable, ("CATEGORY", "STATE", "SUBCATEGORY", "DATE","SQKM", "SPECIES"))

                        #Setup search cursor to go through the input dataset and clip raster to the shape of each feature.
                        #Copy data to the output table
                        with arcpy.da.SearchCursor(WSIClip,(regionField, "SHAPE@", "STATE_NAME")) as cursorin:
                                for row in cursorin:
                                        AOIname = row[0]
                                        AOIshape = row[1]
                                        AOIextent = AOIshape.extent
                                        AOIstate = row[2]
                                        #dealing with odd characters and spaces
                                        AOIname = re.sub("\s+", "", AOIname)
                                        AOIname = AOIname.strip()
                                        AOIname = AOIname.replace("'", "")
                                        AOIname = AOIname.replace("/", "_")
                                        AOIstatea = re.sub("\s+", "", AOIstate)
                                        #print('State: ' + AOIstate + ', AOI: ' + AOIname)
                                        savetemp = AOIstatea + '_' + AOIname + '_' + yearstr

                                        #Process crashes running this try/except.  The except doesn't catch it.
                                        try:
                                                deleteme = Raster(arcpy.gp.ExtractByMask_sa(WSILayerRas, AOIshape))
                                        except:
                                                continue      
                                        deleteme.save(savetemp)

                                        #Add raster to an array for deletion later
                                        datalist.append(deleteme)

                                        #Convert the Extracted raster to a NumPy array and extract desired values
                                        #by incrementing a counter and calculating area.
                                        my_array = arcpy.RasterToNumPyArray(deleteme)
                                        rows, cols = my_array.shape
                                        countAOI = 0
                                        wsikm = 0
                                        #time calculation
                                        for rowNum in xrange(rows):
                                                for colNum in xrange(cols):
                                                        value = my_array.item(rowNum, colNum)
                                                        if value >= 7.2:
                                                              countAOI +=1
                                        wsikm = countAOI * 1024

                                        #write to the output Table
                                        cursorout.insertRow((Region,AOIstate, AOIname, datestr, wsikm, Species))

                                        #Cleanup the geodatabase   
##                                print('Cleaning up')                                        
                                        arcpy.Delete_management(savetemp)
                                        datasetList = arcpy.ListDatasets("Extract_W*", "Raster")
                                        try:
                                                for dataset in datasetList:
                                                        arcpy.Delete_management(dataset)
                                        except:
                                                continue

                        #attempts at fixing the error
                        deleteme = None
                        del cursorout
                        del cursorin

                        #Finish calculating time processing 1 entire year
                        stop = timeit.default_timer()
                        print stop - start
        except Exception as e:
                #print sys.exc_traceback.tb_lineno
                return e

####
#  MAIN
####
if __name__ == '__main__':
        print('Starting script')
        #Start timing entire process
        start = timeit.default_timer()
        #Year Range
        #Entire dataset
        #yearlist = list(range(1979, 2013))
        #Sample
        yearlist = list(range(1979, 1986))

        #Create pool
        print("Creating pool")
        pool = multiprocessing.Pool(7)
        #Call doCalc and pass the year list

        pool.map(doCalc, yearlist)
##        e = doCalc(1979)
        print("Closing pool")
        pool.close()
        print("Joining pool")
        pool.join()
        #print(e[0])
        stop = timeit.default_timer()
        print stop - start        
        print("Complete")
Was it helpful?

Solution

The fix was found and posted http://forums.arcgis.com/threads/109606-Multiprocessing-script-errors-on-geoprocessing-line-of-code-INFADI-(Missing-Dir)?p=387987&posted=1#post387987

The truck is to set your os.environ("TEMP") as well as TMP uniquely within the process.

def doCalc(year):
        yearstr = str(year)
        import time
        time.sleep(1.1)
        newTempDir = r"C:\temp\gptmpenvr_" + time.strftime('%Y%m%d%H%M%S') + yearstr
        os.mkdir(newTempDir)
        os.environ["TEMP"] = newTempDir
        os.environ["TMP"] = newTempDir

        print('Starting doCalc: ' + yearstr)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top