grid.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. # -*- coding: utf-8 -*-
  2. from __future__ import (nested_scopes, generators, division, absolute_import,
  3. with_statement, print_function, unicode_literals)
  4. import os
  5. import sys
  6. import multiprocessing as mltp
  7. import subprocess as sub
  8. import shutil as sht
  9. from grass.script.setup import write_gisrc
  10. from grass.pygrass.gis import Mapset, Location
  11. from grass.pygrass.gis.region import Region
  12. from grass.pygrass.modules import Module
  13. from grass.pygrass.utils import get_mapset_raster, findmaps
  14. from grass.pygrass.modules.grid.split import split_region_tiles
  15. from grass.pygrass.modules.grid.patch import rpatch_map
  16. def select(parms, ptype):
  17. """Select only a certain type of parameters.
  18. :param parms: a DictType parameter with inputs or outputs of a Module class
  19. :type parms: DictType parameters
  20. :param ptype: String define the type of parameter that we want to select,
  21. valid ptype are: 'raster', 'vector', 'group'
  22. :type ptype: str
  23. :returns: An iterator with the value of the parameter.
  24. >>> slp = Module('r.slope.aspect',
  25. ... elevation='ele', slope='slp', aspect='asp',
  26. ... run_=False)
  27. >>> for rast in select(slp.outputs, 'raster'):
  28. ... print(rast)
  29. ...
  30. slp
  31. asp
  32. """
  33. for k in parms:
  34. par = parms[k]
  35. if par.type == ptype or par.typedesc == ptype and par.value:
  36. if par.multiple:
  37. for val in par.value:
  38. yield val
  39. else:
  40. yield par.value
  41. def copy_special_mapset_files(path_src, path_dst):
  42. """Copy all the special GRASS files that are contained in
  43. a mapset to another mapset
  44. :param path_src: the path to the original mapset
  45. :type path_src: str
  46. :param path_dst: the path to the new mapset
  47. :type path_dst: str
  48. """
  49. for fil in (fi for fi in os.listdir(path_src) if fi.isupper()):
  50. sht.copy(os.path.join(path_src, fil), path_dst)
  51. def copy_mapset(mapset, path):
  52. """Copy mapset to another place without copying raster and vector data.
  53. :param mapset: a Mapset instance to copy
  54. :type mapset: Mapset object
  55. :param path: path where the new mapset must be copied
  56. :type path: str
  57. :returns: the instance of the new Mapset.
  58. >>> from grass.script.core import gisenv
  59. >>> mname = gisenv()['MAPSET']
  60. >>> mset = Mapset()
  61. >>> mset.name == mname
  62. True
  63. >>> import tempfile as tmp
  64. >>> import os
  65. >>> path = os.path.join(tmp.gettempdir(), 'my_loc', 'my_mset')
  66. >>> copy_mapset(mset, path) # doctest: +ELLIPSIS
  67. Mapset(...)
  68. >>> sorted(os.listdir(path)) # doctest: +ELLIPSIS
  69. [...'PERMANENT'...]
  70. >>> sorted(os.listdir(os.path.join(path, 'PERMANENT')))
  71. ['DEFAULT_WIND', 'PROJ_INFO', 'PROJ_UNITS', 'VAR', 'WIND']
  72. >>> sorted(os.listdir(os.path.join(path, mname))) # doctest: +ELLIPSIS
  73. [...'SEARCH_PATH',...'WIND']
  74. >>> import shutil
  75. >>> shutil.rmtree(path)
  76. """
  77. per_old = os.path.join(mapset.gisdbase, mapset.location, 'PERMANENT')
  78. per_new = os.path.join(path, 'PERMANENT')
  79. map_old = mapset.path()
  80. map_new = os.path.join(path, mapset.name)
  81. if not os.path.isdir(per_new):
  82. os.makedirs(per_new)
  83. if not os.path.isdir(map_new):
  84. os.mkdir(map_new)
  85. copy_special_mapset_files(per_old, per_new)
  86. copy_special_mapset_files(map_old, map_new)
  87. gisdbase, location = os.path.split(path)
  88. return Mapset(mapset.name, location, gisdbase)
  89. def read_gisrc(gisrc):
  90. """Read a GISRC file and return a tuple with the mapset, location
  91. and gisdbase.
  92. :param gisrc: the path to GISRC file
  93. :type gisrc: str
  94. :returns: a tuple with the mapset, location and gisdbase
  95. >>> import os
  96. >>> from grass.script.core import gisenv
  97. >>> genv = gisenv()
  98. >>> (read_gisrc(os.environ['GISRC']) == (genv['MAPSET'],
  99. ... genv['LOCATION_NAME'],
  100. ... genv['GISDBASE']))
  101. True
  102. """
  103. with open(gisrc, 'r') as gfile:
  104. gis = dict([(k.strip(), v.strip())
  105. for k, v in [row.split(':', 1) for row in gfile]])
  106. return gis['MAPSET'], gis['LOCATION_NAME'], gis['GISDBASE']
  107. def get_mapset(gisrc_src, gisrc_dst):
  108. """Get mapset from a GISRC source to a GISRC destination.
  109. :param gisrc_src: path to the GISRC source
  110. :type gisrc_src: str
  111. :param gisrc_dst: path to the GISRC destination
  112. :type gisrc_dst: str
  113. :returns: a tuple with Mapset(src), Mapset(dst)
  114. """
  115. msrc, lsrc, gsrc = read_gisrc(gisrc_src)
  116. mdst, ldst, gdst = read_gisrc(gisrc_dst)
  117. path_src = os.path.join(gsrc, lsrc, msrc)
  118. path_dst = os.path.join(gdst, ldst, mdst)
  119. if not os.path.isdir(path_dst):
  120. os.makedirs(path_dst)
  121. copy_special_mapset_files(path_src, path_dst)
  122. src = Mapset(msrc, lsrc, gsrc)
  123. dst = Mapset(mdst, ldst, gdst)
  124. visible = [m for m in src.visible]
  125. if src.name not in visible:
  126. visible.append(src.name)
  127. dst.visible.extend(visible)
  128. return src, dst
  129. def copy_groups(groups, gisrc_src, gisrc_dst, region=None):
  130. """Copy group from one mapset to another, crop the raster to the region
  131. :param groups: a list of strings with the group that must be copied
  132. from a master to another.
  133. :type groups: list of strings
  134. :param gisrc_src: path of the GISRC file from where we want to copy the groups
  135. :type gisrc_src: str
  136. :param gisrc_dst: path of the GISRC file where the groups will be created
  137. :type gisrc_dst: str
  138. :param region: a region like object or a dictionary with the region
  139. parameters that will be used to crop the rasters of the
  140. groups
  141. :type region: Region object or dictionary
  142. :returns: None
  143. """
  144. def rmloc(r):
  145. return r.split('@')[0] if '@' in r else r
  146. env = os.environ.copy()
  147. # instantiate modules
  148. get_grp = Module('i.group', flags='lg', stdout_=sub.PIPE, run_=False)
  149. set_grp = Module('i.group')
  150. get_grp.run_ = True
  151. src = read_gisrc(gisrc_src)
  152. dst = read_gisrc(gisrc_dst)
  153. rm = True if src[2] != dst[2] else False
  154. all_rasts = [r[0]
  155. for r in findmaps('raster', location=dst[1], gisdbase=dst[2])]
  156. for grp in groups:
  157. # change gisdbase to src
  158. env['GISRC'] = gisrc_src
  159. get_grp(group=grp, env_=env)
  160. rasts = [r for r in get_grp.outputs.stdout.split()]
  161. # change gisdbase to dst
  162. env['GISRC'] = gisrc_dst
  163. rast2cp = [r for r in rasts if rmloc(r) not in all_rasts]
  164. if rast2cp:
  165. copy_rasters(rast2cp, gisrc_src, gisrc_dst, region=region)
  166. set_grp(group=grp,
  167. input=[rmloc(r) for r in rasts] if rast2cp or rm else rasts,
  168. env_=env)
  169. def set_region(region, gisrc_src, gisrc_dst, env):
  170. """Set a region into two different mapsets.
  171. :param region: a region like object or a dictionary with the region
  172. parameters that will be used to crop the rasters of the
  173. groups
  174. :type region: Region object or dictionary
  175. :param gisrc_src: path of the GISRC file from where we want to copy the groups
  176. :type gisrc_src: str
  177. :param gisrc_dst: path of the GISRC file where the groups will be created
  178. :type gisrc_dst: str
  179. :param env:
  180. :type env:
  181. :returns: None
  182. """
  183. reg_str = "g.region n=%(north)r s=%(south)r " \
  184. "e=%(east)r w=%(west)r " \
  185. "nsres=%(nsres)r ewres=%(ewres)r"
  186. reg_cmd = reg_str % dict(region.items())
  187. env['GISRC'] = gisrc_src
  188. sub.Popen(reg_cmd, shell=True, env=env)
  189. env['GISRC'] = gisrc_dst
  190. sub.Popen(reg_cmd, shell=True, env=env)
  191. def copy_rasters(rasters, gisrc_src, gisrc_dst, region=None):
  192. """Copy rasters from one mapset to another, crop the raster to the region.
  193. :param rasters: a list of strings with the raster map that must be copied
  194. from a master to another.
  195. :type rasters: list
  196. :param gisrc_src: path of the GISRC file from where we want to copy the groups
  197. :type gisrc_src: str
  198. :param gisrc_dst: path of the GISRC file where the groups will be created
  199. :type gisrc_dst: str
  200. :param region: a region like object or a dictionary with the region
  201. parameters that will be used to crop the rasters of the
  202. groups
  203. :type region: Region object or dictionary
  204. :returns: None
  205. """
  206. env = os.environ.copy()
  207. if region:
  208. set_region(region, gisrc_src, gisrc_dst, env)
  209. path_dst = os.path.join(*read_gisrc(gisrc_dst)[::-1])
  210. nam = "copy%d__%s" % (id(gisrc_dst), '%s')
  211. # instantiate modules
  212. mpclc = Module('r.mapcalc')
  213. rpck = Module('r.pack')
  214. rupck = Module('r.unpack')
  215. remove = Module('g.remove')
  216. for rast in rasters:
  217. rast_clean = rast.split('@')[0] if '@' in rast else rast
  218. # change gisdbase to src
  219. env['GISRC'] = gisrc_src
  220. name = nam % rast_clean
  221. mpclc(expression="%s=%s" % (name, rast), overwrite=True, env_=env)
  222. file_dst = "%s.pack" % os.path.join(path_dst, name)
  223. rpck(input=name, output=file_dst, overwrite=True, env_=env)
  224. remove(flags='f', type='raster', name=name, env_=env)
  225. # change gisdbase to dst
  226. env['GISRC'] = gisrc_dst
  227. rupck(input=file_dst, output=rast_clean, overwrite=True, env_=env)
  228. os.remove(file_dst)
  229. def copy_vectors(vectors, gisrc_src, gisrc_dst):
  230. """Copy vectors from one mapset to another, crop the raster to the region.
  231. :param vectors: a list of strings with the vector map that must be copied
  232. from a master to another.
  233. :type vectors: list
  234. :param gisrc_src: path of the GISRC file from where we want to copy the groups
  235. :type gisrc_src: str
  236. :param gisrc_dst: path of the GISRC file where the groups will be created
  237. :type gisrc_dst: str
  238. :returns: None
  239. """
  240. env = os.environ.copy()
  241. path_dst = os.path.join(*read_gisrc(gisrc_dst))
  242. nam = "copy%d__%s" % (id(gisrc_dst), '%s')
  243. # instantiate modules
  244. vpck = Module('v.pack')
  245. vupck = Module('v.unpack')
  246. remove = Module('g.remove')
  247. for vect in vectors:
  248. # change gisdbase to src
  249. env['GISRC'] = gisrc_src
  250. name = nam % vect
  251. file_dst = "%s.pack" % os.path.join(path_dst, name)
  252. vpck(input=name, output=file_dst, overwrite=True, env_=env)
  253. remove(flags='f', type='vector', name=name, env_=env)
  254. # change gisdbase to dst
  255. env['GISRC'] = gisrc_dst
  256. vupck(input=file_dst, output=vect, overwrite=True, env_=env)
  257. os.remove(file_dst)
  258. def get_cmd(cmdd):
  259. """Transform a cmd dictionary to a list of parameters. It is useful to
  260. pickle a Module class and cnvert into a string that can be used with
  261. `Popen(get_cmd(cmdd), shell=True)`.
  262. :param cmdd: a module dictionary with all the parameters
  263. :type cmdd: dict
  264. >>> slp = Module('r.slope.aspect',
  265. ... elevation='ele', slope='slp', aspect='asp',
  266. ... overwrite=True, run_=False)
  267. >>> get_cmd(slp.get_dict()) # doctest: +ELLIPSIS
  268. ['r.slope.aspect', 'elevation=ele', 'format=degrees', ..., '--o']
  269. """
  270. cmd = [cmdd['name'], ]
  271. cmd.extend(("%s=%s" % (k, v) for k, v in cmdd['inputs']
  272. if not isinstance(v, list)))
  273. cmd.extend(("%s=%s" % (k, ','.join(vals if isinstance(vals[0], str)
  274. else [repr(v) for v in vals]))
  275. for k, vals in cmdd['inputs']
  276. if isinstance(vals, list)))
  277. cmd.extend(("%s=%s" % (k, v) for k, v in cmdd['outputs']
  278. if not isinstance(v, list)))
  279. cmd.extend(("%s=%s" % (k, ','.join([repr(v) for v in vals]))
  280. for k, vals in cmdd['outputs'] if isinstance(vals, list)))
  281. cmd.extend(("-%s" % (flg) for flg in cmdd['flags'] if len(flg) == 1))
  282. cmd.extend(("--%s" % (flg[0]) for flg in cmdd['flags'] if len(flg) > 1))
  283. return cmd
  284. def cmd_exe(args):
  285. """Create a mapset, and execute a cmd inside.
  286. :param args: is a tuple that contains several information see below
  287. :type args: tuple
  288. :returns: None
  289. The puple has to contain:
  290. - bbox (dict): a dict with the region parameters (n, s, e, w, etc.)
  291. that we want to set before to apply the command.
  292. - mapnames (dict): a dictionary to substitute the input if the domain has
  293. been split in several tiles.
  294. - gisrc_src (str): path of the GISRC file from where we want to copy the
  295. groups.
  296. - gisrc_dst (str): path of the GISRC file where the groups will be created.
  297. - cmd (dict): a dictionary with all the parameter of a GRASS module.
  298. - groups (list): a list of strings with the groups that we want to copy in
  299. the mapset.
  300. """
  301. bbox, mapnames, gisrc_src, gisrc_dst, cmd, groups = args
  302. src, dst = get_mapset(gisrc_src, gisrc_dst)
  303. env = os.environ.copy()
  304. env['GISRC'] = gisrc_dst
  305. shell = True if sys.platform == 'win32' else False
  306. if mapnames:
  307. inputs = dict(cmd['inputs'])
  308. # reset the inputs to
  309. for key in mapnames:
  310. inputs[key] = mapnames[key]
  311. cmd['inputs'] = inputs.items()
  312. # set the region to the tile
  313. sub.Popen(['g.region', 'raster=%s' % key], shell=shell, env=env).wait()
  314. else:
  315. # set the computational region
  316. lcmd = ['g.region', ]
  317. lcmd.extend(["%s=%s" % (k, v) for k, v in bbox.items()])
  318. sub.Popen(lcmd, shell=shell, env=env).wait()
  319. if groups:
  320. copy_groups(groups, gisrc_src, gisrc_dst)
  321. # run the grass command
  322. sub.Popen(get_cmd(cmd), shell=shell, env=env).wait()
  323. # remove temp GISRC
  324. os.remove(gisrc_dst)
  325. class GridModule(object):
  326. # TODO maybe also i.* could be supported easily
  327. """Run GRASS raster commands in a multiprocessing mode.
  328. :param cmd: raster GRASS command, only command staring with r.* are valid.
  329. :type cmd: str
  330. :param width: width of the tile, in pixel
  331. :type width: int
  332. :param height: height of the tile, in pixel.
  333. :type height: int
  334. :param overlap: overlap between tiles, in pixel.
  335. :type overlap: int
  336. :param processes: number of threads, default value is equal to the number
  337. of processor available.
  338. :param split: if True use r.tile to split all the inputs.
  339. :type split: bool
  340. :param mapset_prefix: if specified created mapsets start with this prefix
  341. :type mapset_prefix: str
  342. :param run_: if False only instantiate the object
  343. :type run_: bool
  344. :param args: give all the parameters to the command
  345. :param kargs: give all the parameters to the command
  346. >>> grd = GridModule('r.slope.aspect',
  347. ... width=500, height=500, overlap=2,
  348. ... processes=None, split=False,
  349. ... elevation='elevation',
  350. ... slope='slope', aspect='aspect', overwrite=True)
  351. >>> grd.run()
  352. """
  353. def __init__(self, cmd, width=None, height=None, overlap=0, processes=None,
  354. split=False, debug=False, region=None, move=None, log=False,
  355. start_row=0, start_col=0, out_prefix='', mapset_prefix=None,
  356. *args, **kargs):
  357. kargs['run_'] = False
  358. self.mset = Mapset()
  359. self.module = Module(cmd, *args, **kargs)
  360. self.width = width
  361. self.height = height
  362. self.overlap = overlap
  363. self.processes = processes
  364. self.region = region if region else Region()
  365. self.start_row = start_row
  366. self.start_col = start_col
  367. self.out_prefix = out_prefix
  368. self.log = log
  369. self.move = move
  370. self.gisrc_src = os.environ['GISRC']
  371. self.n_mset, self.gisrc_dst = None, None
  372. if self.move:
  373. self.n_mset = copy_mapset(self.mset, self.move)
  374. self.gisrc_dst = write_gisrc(self.n_mset.gisdbase,
  375. self.n_mset.location,
  376. self.n_mset.name)
  377. rasters = [r for r in select(self.module.inputs, 'raster')]
  378. if rasters:
  379. copy_rasters(rasters, self.gisrc_src, self.gisrc_dst,
  380. region=self.region)
  381. vectors = [v for v in select(self.module.inputs, 'vector')]
  382. if vectors:
  383. copy_vectors(vectors, self.gisrc_src, self.gisrc_dst)
  384. groups = [g for g in select(self.module.inputs, 'group')]
  385. if groups:
  386. copy_groups(groups, self.gisrc_src, self.gisrc_dst,
  387. region=self.region)
  388. self.bboxes = split_region_tiles(region=region,
  389. width=width, height=height,
  390. overlap=overlap)
  391. if mapset_prefix:
  392. self.msetstr = mapset_prefix + "_%03d_%03d"
  393. else:
  394. self.msetstr = cmd.replace('.', '') + "_%03d_%03d"
  395. self.inlist = None
  396. if split:
  397. self.split()
  398. self.debug = debug
  399. def __del__(self):
  400. if self.gisrc_dst:
  401. # remove GISRC file
  402. os.remove(self.gisrc_dst)
  403. def clean_location(self, location=None):
  404. """Remove all created mapsets.
  405. :param location: a Location instance where we are running the analysis
  406. :type location: Location object
  407. """
  408. if location is None:
  409. if self.n_mset:
  410. self.n_mset.current()
  411. location = Location()
  412. mapsets = location.mapsets(self.msetstr.split('_')[0] + '_*')
  413. for mset in mapsets:
  414. Mapset(mset).delete()
  415. if self.n_mset and self.n_mset.is_current():
  416. self.mset.current()
  417. def split(self):
  418. """Split all the raster inputs using r.tile"""
  419. rtile = Module('r.tile')
  420. inlist = {}
  421. for inm in select(self.module.inputs, 'raster'):
  422. rtile(input=inm.value, output=inm.value,
  423. width=self.width, height=self.height,
  424. overlap=self.overlap)
  425. patt = '%s-*' % inm.value
  426. inlist[inm.value] = sorted(self.mset.glist(type='raster',
  427. pattern=patt))
  428. self.inlist = inlist
  429. def get_works(self):
  430. """Return a list of tuble with the parameters for cmd_exe function"""
  431. works = []
  432. reg = Region()
  433. if self.move:
  434. mdst, ldst, gdst = read_gisrc(self.gisrc_dst)
  435. else:
  436. ldst, gdst = self.mset.location, self.mset.gisdbase
  437. cmd = self.module.get_dict()
  438. groups = [g for g in select(self.module.inputs, 'group')]
  439. for row, box_row in enumerate(self.bboxes):
  440. for col, box in enumerate(box_row):
  441. inms = None
  442. if self.inlist:
  443. inms = {}
  444. cols = len(box_row)
  445. for key in self.inlist:
  446. indx = row * cols + col
  447. inms[key] = "%s@%s" % (self.inlist[key][indx],
  448. self.mset.name)
  449. # set the computational region, prepare the region parameters
  450. bbox = dict([(k[0], str(v)) for k, v in box.items()[:-2]])
  451. bbox['nsres'] = '%f' % reg.nsres
  452. bbox['ewres'] = '%f' % reg.ewres
  453. new_mset = self.msetstr % (self.start_row + row,
  454. self.start_col + col),
  455. works.append((bbox, inms,
  456. self.gisrc_src,
  457. write_gisrc(gdst, ldst, new_mset),
  458. cmd, groups))
  459. return works
  460. def define_mapset_inputs(self):
  461. """Add the mapset information to the input maps
  462. """
  463. for inmap in self.module.inputs:
  464. inm = self.module.inputs[inmap]
  465. if inm.type in ('raster', 'vector') and inm.value:
  466. if '@' not in inm.value:
  467. mset = get_mapset_raster(inm.value)
  468. inm.value = inm.value + '@%s' % mset
  469. def run(self, patch=True, clean=True):
  470. """Run the GRASS command
  471. :param patch: set False if you does not want to patch the results
  472. :type patch: bool
  473. :param clean: set False if you does not want to remove all the stuff
  474. created by GridModule
  475. :type clean: bool
  476. """
  477. self.module.flags.overwrite = True
  478. self.define_mapset_inputs()
  479. if self.debug:
  480. for wrk in self.get_works():
  481. cmd_exe(wrk)
  482. else:
  483. pool = mltp.Pool(processes=self.processes)
  484. result = pool.map_async(cmd_exe, self.get_works())
  485. result.wait()
  486. pool.close()
  487. pool.join()
  488. if not result.successful():
  489. raise RuntimeError(_("Execution of subprocesses was not successful"))
  490. if patch:
  491. if self.move:
  492. os.environ['GISRC'] = self.gisrc_dst
  493. self.n_mset.current()
  494. self.patch()
  495. os.environ['GISRC'] = self.gisrc_src
  496. self.mset.current()
  497. # copy the outputs from dst => src
  498. routputs = [self.out_prefix + o
  499. for o in select(self.module.outputs, 'raster')]
  500. copy_rasters(routputs, self.gisrc_dst, self.gisrc_src)
  501. else:
  502. self.patch()
  503. if self.log:
  504. # record in the temp directory
  505. from grass.lib.gis import G_tempfile
  506. tmp, dummy = os.path.split(G_tempfile())
  507. tmpdir = os.path.join(tmp, self.module.name)
  508. for k in self.module.outputs:
  509. par = self.module.outputs[k]
  510. if par.typedesc == 'raster' and par.value:
  511. dirpath = os.path.join(tmpdir, par.name)
  512. if not os.path.isdir(dirpath):
  513. os.makedirs(dirpath)
  514. fil = open(os.path.join(dirpath,
  515. self.out_prefix + par.value), 'w+')
  516. fil.close()
  517. if clean:
  518. self.clean_location()
  519. self.rm_tiles()
  520. if self.n_mset:
  521. gisdbase, location = os.path.split(self.move)
  522. self.clean_location(Location(location, gisdbase))
  523. # rm temporary gis_rc
  524. os.remove(self.gisrc_dst)
  525. self.gisrc_dst = None
  526. sht.rmtree(os.path.join(self.move, 'PERMANENT'))
  527. sht.rmtree(os.path.join(self.move, self.mset.name))
  528. def patch(self):
  529. """Patch the final results."""
  530. bboxes = split_region_tiles(width=self.width, height=self.height)
  531. loc = Location()
  532. mset = loc[self.mset.name]
  533. mset.visible.extend(loc.mapsets())
  534. noutputs = 0
  535. for otmap in self.module.outputs:
  536. otm = self.module.outputs[otmap]
  537. if otm.typedesc == 'raster' and otm.value:
  538. rpatch_map(otm.value,
  539. self.mset.name, self.msetstr, bboxes,
  540. self.module.flags.overwrite,
  541. self.start_row, self.start_col, self.out_prefix)
  542. noutputs += 1
  543. if noutputs < 1:
  544. msg = 'No raster output option defined for <{}>'.format(self.module.name)
  545. if self.module.name == 'r.mapcalc':
  546. msg += '. Use <{}.simple> instead'.format(self.module.name)
  547. raise RuntimeError(msg)
  548. def rm_tiles(self):
  549. """Remove all the tiles."""
  550. # if split, remove tiles
  551. if self.inlist:
  552. grm = Module('g.remove')
  553. for key in self.inlist:
  554. grm(flags='f', type='raster', name=self.inlist[key])