Un requisito comune in GIS è applicare uno strumento di elaborazione a un numero di file o applicare un processo per una serie di funzioni in un file a un altro file.
Molte di queste operazioni sono imbarazzantemente parallele in quanto i risultati dei calcoli non influenzano in alcun modo qualsiasi altra operazione nel ciclo. Non solo, ma spesso i file di input sono distinti.
Un classico esempio è la piastrellatura dei file di forma rispetto ai file contenenti poligoni per agganciarli.
Ecco un metodo procedurale classico (testato) per raggiungere questo obiettivo in uno script Python per QGIS. (grazie all'output di file di memoria temporanei su file reali più che dimezzato il tempo di elaborazione dei miei file di test)
import processing
import os
input_file="/path/to/input_file.shp"
clip_polygons_file="/path/to/polygon_file.shp"
output_folder="/tmp/test/"
input_layer = QgsVectorLayer(input_file, "input file", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(input_layer)
tile_layer = QgsVectorLayer(clip_polygons_file, "clip_polys", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(tile_layer)
tile_layer_dp=input_layer.dataProvider()
EPSG_code=int(tile_layer_dp.crs().authid().split(":")[1])
tile_no=0
clipping_polygons = tile_layer.getFeatures()
for clipping_polygon in clipping_polygons:
print "Tile no: "+str(tile_no)
tile_no+=1
geom = clipping_polygon.geometry()
clip_layer=QgsVectorLayer("Polygon?crs=epsg:"+str(EPSG_code)+\
"&field=id:integer&index=yes","clip_polygon", "memory")
clip_layer_dp = clip_layer.dataProvider()
clip_layer.startEditing()
clip_layer_feature = QgsFeature()
clip_layer_feature.setGeometry(geom)
(res, outFeats) = clip_layer_dp.addFeatures([clip_layer_feature])
clip_layer.commitChanges()
clip_file = os.path.join(output_folder,"tile_"+str(tile_no)+".shp")
write_error = QgsVectorFileWriter.writeAsVectorFormat(clip_layer, \
clip_file, "system", \
QgsCoordinateReferenceSystem(EPSG_code), "ESRI Shapefile")
QgsMapLayerRegistry.instance().addMapLayer(clip_layer)
output_file = os.path.join(output_folder,str(tile_no)+".shp")
processing.runalg("qgis:clip", input_file, clip_file, output_file)
QgsMapLayerRegistry.instance().removeMapLayer(clip_layer.id())
Questo andrebbe bene, tranne per il fatto che il mio file di input è 2 GB e il file di ritaglio poligonale contiene oltre 400 poligoni. Il processo risultante richiede più di una settimana sulla mia macchina quad core. Nel frattempo tre core sono solo inattivi.
La soluzione che ho in testa è esportare il processo in file di script ed eseguirli in modo asincrono usando ad esempio gnu parallel. Tuttavia, sembra un peccato dover abbandonare QGIS in una soluzione specifica del sistema operativo anziché utilizzare qualcosa di nativo di QGIS Python. Quindi la mia domanda è:
Posso parallelizzare in modo nativo operazioni geografiche imbarazzanti all'interno di Python QGIS?
In caso contrario, forse qualcuno ha già il codice per inviare questo tipo di lavoro agli script shell asincroni?