Grass engine refactoring, volume calculations using python

pull/835/head
Piero Toffanin 2020-02-29 22:01:15 -05:00
rodzic 16b8e03fd5
commit 5c5aa188da
4 zmienionych plików z 103 dodań i 60 usunięć

Wyświetl plik

@ -4,8 +4,6 @@ import tempfile
import subprocess
import os
from string import Template
from webodm import settings
logger = logging.getLogger('app.logger')
@ -30,12 +28,12 @@ class GrassEngine:
class GrassContext:
def __init__(self, grass_binary, tmpdir = None, template_args = {}, location = None, auto_cleanup=True):
def __init__(self, grass_binary, tmpdir = None, script_opts = {}, location = None, auto_cleanup=True):
self.grass_binary = grass_binary
if tmpdir is None:
tmpdir = os.path.basename(tempfile.mkdtemp('_grass_engine', dir=settings.MEDIA_TMP))
self.tmpdir = tmpdir
self.template_args = template_args
self.script_opts = script_opts
self.location = location
self.auto_cleanup = auto_cleanup
@ -48,15 +46,15 @@ class GrassContext:
dst_path = os.path.abspath(os.path.join(self.get_cwd(), filename))
with open(dst_path, 'w') as f:
f.write(source)
self.template_args[param] = dst_path
self.script_opts[param] = dst_path
if use_as_location:
self.set_location(self.template_args[param])
self.set_location(self.script_opts[param])
return dst_path
def add_param(self, param, value):
self.template_args[param] = value
self.script_opts[param] = value
def set_location(self, location):
"""
@ -75,25 +73,12 @@ class GrassContext:
script = os.path.abspath(script)
# Create grass script via template substitution
try:
with open(script) as f:
script_content = f.read()
except FileNotFoundError:
raise GrassEngineException("Script does not exist: {}".format(script))
tmpl = Template(script_content)
# Write script to disk
if not os.path.exists(self.get_cwd()):
os.mkdir(self.get_cwd())
with open(os.path.join(self.get_cwd(), 'script.sh'), 'w') as f:
f.write(tmpl.substitute(self.template_args))
# Create param list
params = ["{}={}".format(opt,value) for opt,value in self.script_opts.items()]
# Execute it
logger.info("Executing grass script from {}: {} -c {} location --exec sh script.sh".format(self.get_cwd(), self.grass_binary, self.location))
p = subprocess.Popen([self.grass_binary, '-c', self.location, 'location', '--exec', 'sh', 'script.sh'],
logger.info("Executing grass script from {}: {} -c {} location --exec python {} {}".format(self.get_cwd(), self.grass_binary, self.location, script, " ".join(params)))
p = subprocess.Popen([self.grass_binary, '-c', self.location, 'location', '--exec', 'python', script] + params,
cwd=self.get_cwd(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
@ -108,14 +93,15 @@ class GrassContext:
def serialize(self):
return {
'tmpdir': self.tmpdir,
'template_args': self.template_args,
'script_opts': self.script_opts,
'location': self.location,
'auto_cleanup': self.auto_cleanup
}
def cleanup(self):
if os.path.exists(self.get_cwd()):
shutil.rmtree(self.get_cwd())
pass
# if os.path.exists(self.get_cwd()):
# shutil.rmtree(self.get_cwd())
def __del__(self):
if self.auto_cleanup:

Wyświetl plik

@ -41,7 +41,7 @@ class TaskVolume(TaskView):
celery_task_id = execute_grass_script.delay(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"calc_volume.grass"
"calc_volume.py"
), context.serialize()).task_id
return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)

Wyświetl plik

@ -1,32 +0,0 @@
# area_file: Geospatial file containing the area to measure
# points_file: Geospatial file containing the points defining the area
# dsm_file: GeoTIFF DEM containing the surface
# ------
# output: prints the volume to stdout
#Import raster and vector
v.import input=${area_file} output=polygon_area --overwrite
v.import input=${points_file} output=polygon_points --overwrite
v.buffer -s --overwrite input=polygon_area type=area output=region distance=1 minordistance=1
r.external input=${dsm_file} output=dsm --overwrite
# Set Grass region to vector bbox
g.region vector=region
# Create a mask to speed up computation
r.mask vect=region
# Transfer dsm raster data to vector
v.what.rast map=polygon_points raster=dsm column=height
# Decimate DSM and generate interpolation of new terrain
v.surf.rst --overwrite input=polygon_points zcolumn=height elevation=dsm_below_pile
# Compute difference between dsm and new dsm
r.mapcalc expression='pile_height_above_dsm=dsm-dsm_below_pile' --overwrite
# Set region to polygon area to calculate volume
g.region vect=polygon_area
# Volume output from difference
r.volume -f input=pile_height_above_dsm

Wyświetl plik

@ -0,0 +1,89 @@
#%module
#% description: Calculate volume of area and prints the volume to stdout
#%end
#%option
#% key: area_file
#% type: string
#% required: yes
#% multiple: no
#% description: Geospatial file containing the area to measure
#%end
#%option
#% key: points_file
#% type: string
#% required: yes
#% multiple: no
#% description: Geospatial file containing the points defining the area
#%end
#%option
#% key: dsm_file
#% type: string
#% required: yes
#% multiple: no
#% description: GeoTIFF DEM containing the surface
#%end
import sys
from grass.pygrass.modules import Module
import grass.script as grass
def main():
# Import raster and vector
Module("v.import", input=opts['area_file'], output="polygon_area", overwrite=True)
Module("v.import", input=opts['points_file'], output="polygon_points", overwrite=True)
Module("v.buffer", input="polygon_area", s=True, type="area", output="region", distance=1, minordistance=1, overwrite=True)
Module("r.external", input=opts['dsm_file'], output="dsm", overwrite=True)
# Set Grass region to vector bbox
Module("g.region", vector="region")
# Create a mask to speed up computation
Module("r.mask", vector="region")
# Transfer dsm raster data to vector
Module("v.what.rast", map="polygon_points", raster="dsm", column="height")
# Decimate DSM and generate interpolation of new terrain
Module("v.surf.rst", input="polygon_points", zcolumn="height", elevation="dsm_below_pile", overwrite=True)
# Compute difference between dsm and new dsm
Module("r.mapcalc", expression='pile_height_above_dsm=dsm-dsm_below_pile', overwrite=True)
# Set region to polygon area to calculate volume
Module("g.region", vector="polygon_area")
# Volume output from difference
Module("r.volume", input="pile_height_above_dsm", f=True)
return 0
if __name__ == "__main__":
opts, _ = grass.parser()
sys.exit(main())
#Import raster and vector
# v.import input=${area_file} output=polygon_area --overwrite
# v.import input=${points_file} output=polygon_points --overwrite
# v.buffer -s --overwrite input=polygon_area type=area output=region distance=1 minordistance=1
# r.external input=${dsm_file} output=dsm --overwrite
#
# # Set Grass region to vector bbox
# g.region vector=region
#
# # Create a mask to speed up computation
# r.mask vect=region
#
# # Transfer dsm raster data to vector
# v.what.rast map=polygon_points raster=dsm column=height
#
# # Decimate DSM and generate interpolation of new terrain
# v.surf.rst --overwrite input=polygon_points zcolumn=height elevation=dsm_below_pile
#
# # Compute difference between dsm and new dsm
# r.mapcalc expression='pile_height_above_dsm=dsm-dsm_below_pile' --overwrite
#
# # Set region to polygon area to calculate volume
# g.region vect=polygon_area
#
# # Volume output from difference
# r.volume -f input=pile_height_above_dsm