2016-04-25 14 views
2

Ich mache einige Zahlen in einem Raster mit arcpy Knirschen und möchten das multiprocessing-Paket verwenden, um die Dinge zu beschleunigen. Grundsätzlich muss ich eine Liste von Tupeln durchlaufen, einige Rasterberechnungen mit jedem Tupel durchführen und einige Ausgaben in Dateien schreiben. Meine Eingaben bestehen aus einem Datenraster (Bathymetrie), einem Raster, das Zonen definiert, und einem Tupel aus zwei Schwimmern (Wasseroberflächenhöhe, Tiefe). Meine Prozedur besteht aus einer Funktion computeplane, die ein Tupel nimmt und eine Reihe von Rasterberechnungen ausführt, um fünf Raster zu erzeugen (total, littoral, surface, subsurface, profundal) und dann die Funktion processtable für jedes dieser Raster aufruft, um Werte in a zu schreiben DBF mit arcpy.sa.ZonalStatisticsAsTable, fügen Sie einige Felder mit arcpy.AddField_management, konvertieren Sie die DBF in eine CSV mit arcpy.TableToTable_conversion, und löschen Sie schließlich die DBF-Datei mit arcpy.Delete_management.arcpy + multiprocessing: Fehler: konnte Raster-Datensatz nicht speichern

Basiert auf etwas, ich habe meinen Code in main() so eingewickelt, dass multiprocessing.Pool angeblich nett spielt. Ich benutze main(), um den Satz von Tupeln und pool.map zu erstellen, um das Multiprocessing zu machen. Ich verwende das Paket tempfile, um Namen für die dbf-Datei auszuwählen, um Namenskonflikte zu vermeiden. Die CSV-Dateinamen stehen garantiert nicht in Konflikt mit den anderen Threads.

Ich habe meinen Code mit einer for-Schleife getestet und es funktioniert gut, aber wenn ich versuche pool.map ich zu verwenden

RuntimeError: ERROR 010240: Could not save raster dataset to C:\Users\Michael\AppData\Local\ESRI\Desktop10.4\SpatialAnalyst\lesst_ras with output format GRID.

Was hier geschieht? Dieser Fehler wird nicht in der nicht-multiprocess-Version des Codes angezeigt, und ich schreibe die Raster nirgendwo heraus --- dann wieder weiß ich nicht, wie arcpy mit den Zwischenrastern beschäftigt ist (ich sicher nicht Ich denke, es hält sie im Gedächtnis - sie sind zu groß. Muss ich der arcpy etwas über die Art, wie es die Rasterberechnungen behandelt, damit Multiprocessing funktioniert? Ich habe meine Python-Datei unten eingefügt.

import arcpy 
arcpy.CheckOutExtension("Spatial") 
import arcpy.sa 
import numpy 
import multiprocessing 
import tempfile 
bathymetry_path = r'C:/GIS workspace/RRE/habitat.gdb/bathymetry_NGVD_meters' 
zones_path = r'C:/GIS workspace/RRE/habitat.gdb/markerzones_meters' 
table_folder = r'C:/GIS workspace/RRE/zonetables' 
bathymetry = arcpy.sa.Raster(bathymetry_path) 
zones = arcpy.sa.Raster(zones_path) 

def processtable(raster_obj, zone_file, w, z, out_folder, out_file): 
    temp_name = "/" + next(tempfile._get_candidate_names()) + ".dbf" 
    arcpy.sa.ZonalStatisticsAsTable(zone_file, 'VALUE', raster_obj, out_folder + temp_name, "DATA", "SUM") 
    arcpy.AddField_management(out_folder + temp_name, "wse", 'TEXT') 
    arcpy.AddField_management(out_folder + temp_name, "z", 'TEXT') 
    arcpy.CalculateField_management(out_folder + temp_name, "wse", "'" + str(w) + "'", "PYTHON") 
    arcpy.CalculateField_management(out_folder + temp_name, "z", "'" + str(z) + "'", "PYTHON") 
    arcpy.TableToTable_conversion(out_folder + temp_name, out_folder, out_file) 
    arcpy.Delete_management(out_folder + temp_name) 

def computeplane(wsedepth): 
    wse = wsedepth[0] 
    depth = wsedepth[1] 
    total = bathymetry < depth 
    littoral = total & ((wse - bathymetry) < 2) 
    surface = total & ~(littoral) & ((total + wse - depth) < (total + 2)) 
    profundal = total & ((total + wse - depth) > (total + 5)) 
    subsurface = total & ~(profundal | surface | littoral) 
    # zonal statistics table names 
    total_name = 'total_w' + str(wse) + '_z' + str(depth) + '.csv' 
    littoral_name = 'littoral_w' + str(wse) + '_z' + str(depth) + '.csv' 
    surface_name = 'surface_w' + str(wse) + '_z' + str(depth) + '.csv' 
    subsurface_name = 'subsurface_w' + str(wse) + '_z' + str(depth) + '.csv' 
    profundal_name = 'profundal_w' + str(wse) + '_z' + str(depth) + '.csv' 
    # compute zonal statistics 
    processtable(total, zones, wse, depth, table_folder, total_name) 
    processtable(littoral, zones, wse, depth, table_folder, littoral_name) 
    processtable(surface, zones, wse, depth, table_folder, surface_name) 
    processtable(profundal, zones, wse, depth, table_folder, profundal_name) 
    processtable(subsurface, zones, wse, depth, table_folder, subsurface_name) 

def main(): 
    watersurface = numpy.arange(-15.8, 2.7, 0.1) 
    # take small subset of the tuples: watersurface[33:34] 
    wsedepths = [(watersurface[x], watersurface[y]) for x in range(watersurface.size)[33:34] for y in range(watersurface[0:x+1].size)] 
    pool = multiprocessing.Pool() 
    pool.map(computeplane, wsedepths) 
    pool.close() 
    pool.join() 

if __name__ == '__main__': 
    main() 

UPDATE

Einige mehr sleuthing zeigt, dass dies nicht so sehr mit der Art und Weise multiprocessing Problem als ein Problem ist, dass ArcGIS Rasterverarbeitung der Fall ist. Rasteralgebra-Ergebnisse werden in Dateien im Standardarbeitsbereich geschrieben. In meinem Fall hatte ich keinen Ordner angegeben, daher schrieb arcpy die Raster in einen AppData-Ordner. ArcGIS verwendet Basistypen wie Lessth, Lessth1 usw. basierend auf dem, was Ihr Algebraausdruck ist. Da ich keinen Arbeitsbereich angegeben habe, haben alle multiprocessing Threads in diesen Ordner geschrieben. Während ein einzelner arcpy Prozess Namen verfolgen kann, versuchen die mehreren Prozesse alle die gleichen Rasternamen zu schreiben und stoßen auf die Sperren des anderen Prozesses.

Ich habe versucht, eine zufälligen Arbeitsplatz (Datei GDB) zu Beginn der computeplane zu schaffen und es dann am Ende zu löschen, aber arcpy entbindet in der Regel nicht die Sperre in einer angemessenen Art und Weise und der Prozess abstürzt, auf der Delete-Anweisung. Ich bin mir also nicht sicher, wie es weitergehen soll.

Antwort

1

Nun, die Lösung zu ERROR 010240 war, die arcpy.gp.RasterCalculator_sa Funktion anstelle von arcpy.sa zu verwenden, um Raster mit angegebenen Ausgabenamen zu schreiben. Leider nach erneuter Umsetzung lief ich in

FATAL ERROR (INFADI) MISSING DIRECTORY

die in another stackexchange post beschrieben. Die Empfehlungen in diesem Post geben einen anderen Arbeitsbereich in jedem Funktionsaufruf an, der das Erste war, was ich ausprobierte (ohne Erfolg).Es gibt auch eine Diskussion darüber, dass nur ein Raster gleichzeitig ausgeschrieben werden kann, daher ist es ohnehin nicht sinnvoll, Rasterberechnungen zu vervielfältigen. Ich gebe auf!