grid.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Thu Mar 28 11:06:00 2013
  4. @author: pietro
  5. """
  6. import os
  7. import multiprocessing as mltp
  8. import subprocess as sub
  9. from grass.script.setup import write_gisrc
  10. from grass.pygrass.gis import Mapset, Location, make_mapset
  11. from grass.pygrass.modules import Module
  12. from split import split_region_tiles
  13. from patch import patch_map
  14. _GREG = Module('g.region')
  15. def get_cmd(cmdd):
  16. """Transforma a cmd dictionary to a list of parameters"""
  17. cmd = [cmdd['name'], ]
  18. cmd.extend(("%s=%s" % (k, v) for k, v in cmdd['inputs']))
  19. cmd.extend(("%s=%s" % (k, v) for k, v in cmdd['outputs']))
  20. cmd.extend(("%s" % (flg) for flg in cmdd['flags'] if len(flg) == 1))
  21. cmd.extend(("--%s" % (flg[0]) for flg in cmdd['flags'] if len(flg) > 1))
  22. return cmd
  23. def cmd_exe((bbox, mapnames, msetname, cmd)):
  24. """Create a mapset, and execute a cmd inside."""
  25. mset = Mapset()
  26. try:
  27. make_mapset(msetname)
  28. except:
  29. pass
  30. env = os.environ.copy()
  31. env['GISRC'] = write_gisrc(mset.gisdbase, mset.location, msetname)
  32. if mapnames:
  33. inputs = dict(cmd['inputs'])
  34. # reset the inputs to
  35. for key in mapnames:
  36. inputs[key] = mapnames[key]
  37. cmd['inputs'] = inputs.items()
  38. # set the region to the tile
  39. _GREG(env_=env, rast=key)
  40. else:
  41. # set the computational region
  42. _GREG(env_=env, **bbox)
  43. # run the grass command
  44. sub.Popen(get_cmd(cmd), env=env).wait()
  45. class GridModule(object):
  46. """Run GRASS raster commands in a multiproccessing mode.
  47. Parameters
  48. -----------
  49. cmd: raster GRASS command
  50. Only command staring with r.* are valid.
  51. width: integer
  52. Width of the tile, in pixel.
  53. height: integer
  54. Height of the tile, in pixel.
  55. overlap: integer
  56. Overlap between tiles, in pixel.
  57. nthreads: number of threads
  58. Default value is equal to the number of processor available.
  59. split: boolean
  60. If True use r.tile to split all the inputs.
  61. run_: boolean
  62. If False only instantiate the object.
  63. args and kargs: cmd parameters
  64. Give all the parameters to the command.
  65. Examples
  66. --------
  67. ::
  68. >>> grd = GridModule('r.slope.aspect',
  69. ... width=500, height=500, overlap=2,
  70. ... processes=None, split=True,
  71. ... elevation='elevation',
  72. ... slope='slope', aspect='aspect', overwrite=True)
  73. >>> grd.run()
  74. """
  75. def __init__(self, cmd, width=None, height=None, overlap=0, processes=None,
  76. split=False, *args, **kargs):
  77. kargs['run_'] = False
  78. self.mset = Mapset()
  79. self.module = Module(cmd, *args, **kargs)
  80. self.width = width
  81. self.height = height
  82. self.overlap = overlap
  83. self.processes = processes
  84. self.bboxes = split_region_tiles(width=width, height=height,
  85. overlap=overlap)
  86. self.msetstr = cmd.replace('.', '') + "_%03d_%03d"
  87. self.inlist = None
  88. if split:
  89. self.split()
  90. def clean_location(self):
  91. """Remove all created mapsets."""
  92. mapsets = Location().mapsets(self.msetstr.split('_')[0] + '_*')
  93. for mset in mapsets:
  94. Mapset(mset).delete()
  95. def split(self):
  96. """Split all the raster inputs using r.tile"""
  97. rtile = Module('r.tile')
  98. inlist = {}
  99. #import pdb; pdb.set_trace()
  100. for inmap in self.module.inputs:
  101. inm = self.module.inputs[inmap]
  102. if inm.type == 'raster' and inm.value:
  103. rtile(input=inm.value, output=inm.value,
  104. width=self.width, height=self.height,
  105. overlap=self.overlap)
  106. patt = '%s-*' % inm.value
  107. inlist[inm.value] = sorted(self.mset.glist(type='rast',
  108. pattern=patt))
  109. self.inlist = inlist
  110. def get_works(self):
  111. """Return a list of tuble with the parameters for cmd_exe function"""
  112. works = []
  113. cmd = self.module.get_dict()
  114. for row, box_row in enumerate(self.bboxes):
  115. for col, box in enumerate(box_row):
  116. inms = None
  117. if self.inlist:
  118. inms = {}
  119. cols = len(box_row)
  120. for key in self.inlist:
  121. indx = row * cols + col
  122. inms[key] = "%s@%s" % (self.inlist[key][indx],
  123. self.mset.name)
  124. # set the computational region, prepare the region parameters
  125. bbox = dict([(k[0], str(v)) for k, v in box.items()[:-2]])
  126. works.append((bbox, inms, self.msetstr % (row, col), cmd))
  127. return works
  128. def run(self, patch=True, clean=True):
  129. """Run the GRASS command."""
  130. self.module.flags.overwrite = True
  131. pool = mltp.Pool(processes=self.processes)
  132. result = pool.map_async(cmd_exe, self.get_works())
  133. result.wait()
  134. if not result.successful():
  135. raise RuntimeError
  136. if patch:
  137. self.patch()
  138. if clean:
  139. self.clean_location()
  140. self.rm_tiles()
  141. def patch(self):
  142. """Patch the final results."""
  143. # patch all the outputs
  144. for otmap in self.module.outputs:
  145. otm = self.module.outputs[otmap]
  146. if otm.type == 'raster' and otm.value:
  147. patch_map(otm.value, self.mset.name, self.msetstr,
  148. split_region_tiles(width=self.width,
  149. height=self.height),
  150. self.module.flags.overwrite)
  151. def rm_tiles(self):
  152. """Remove all the tiles."""
  153. # if split, remove tiles
  154. if self.inlist:
  155. grm = Module('g.remove')
  156. for key in self.inlist:
  157. grm(rast=self.inlist[key])