grid.py 22 KB

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