temporal_raster_algebra.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. """!@package grass.temporal
  2. Temporal raster algebra
  3. (C) 2013 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. :authors: Thomas Leppelt and Soeren Gebbert
  8. .. code-block:: python
  9. >>> p = TemporalRasterAlgebraLexer()
  10. >>> p.build()
  11. >>> p.debug = True
  12. >>> expression = 'R = A[0,1,0] / B[0,0,1] * 20 + C[0,1,1] - 2.45'
  13. >>> p.test(expression)
  14. R = A[0,1,0] / B[0,0,1] * 20 + C[0,1,1] - 2.45
  15. LexToken(NAME,'R',1,0)
  16. LexToken(EQUALS,'=',1,2)
  17. LexToken(NAME,'A',1,4)
  18. LexToken(L_SPAREN,'[',1,5)
  19. LexToken(INT,0,1,6)
  20. LexToken(COMMA,',',1,7)
  21. LexToken(INT,1,1,8)
  22. LexToken(COMMA,',',1,9)
  23. LexToken(INT,0,1,10)
  24. LexToken(R_SPAREN,']',1,11)
  25. LexToken(DIV,'/',1,13)
  26. LexToken(NAME,'B',1,15)
  27. LexToken(L_SPAREN,'[',1,16)
  28. LexToken(INT,0,1,17)
  29. LexToken(COMMA,',',1,18)
  30. LexToken(INT,0,1,19)
  31. LexToken(COMMA,',',1,20)
  32. LexToken(INT,1,1,21)
  33. LexToken(R_SPAREN,']',1,22)
  34. LexToken(MULT,'*',1,24)
  35. LexToken(INT,20,1,26)
  36. LexToken(ADD,'+',1,29)
  37. LexToken(NAME,'C',1,31)
  38. LexToken(L_SPAREN,'[',1,32)
  39. LexToken(INT,0,1,33)
  40. LexToken(COMMA,',',1,34)
  41. LexToken(INT,1,1,35)
  42. LexToken(COMMA,',',1,36)
  43. LexToken(INT,1,1,37)
  44. LexToken(R_SPAREN,']',1,38)
  45. LexToken(SUB,'-',1,40)
  46. LexToken(FLOAT,2.45,1,42)
  47. """
  48. from __future__ import print_function
  49. try:
  50. import ply.yacc as yacc
  51. except ImportError:
  52. pass
  53. from .temporal_raster_base_algebra import (
  54. TemporalRasterBaseAlgebraParser,
  55. TemporalRasterAlgebraLexer,
  56. )
  57. import grass.pygrass.modules as pymod
  58. from .space_time_datasets import RasterDataset
  59. class TemporalRasterAlgebraParser(TemporalRasterBaseAlgebraParser):
  60. """The temporal raster algebra class"""
  61. def __init__(
  62. self,
  63. pid=None,
  64. run=False,
  65. debug=True,
  66. spatial=False,
  67. register_null=False,
  68. dry_run=False,
  69. nprocs=1,
  70. time_suffix=None,
  71. ):
  72. TemporalRasterBaseAlgebraParser.__init__(
  73. self,
  74. pid=pid,
  75. run=run,
  76. debug=debug,
  77. spatial=spatial,
  78. register_null=register_null,
  79. dry_run=dry_run,
  80. nprocs=nprocs,
  81. time_suffix=time_suffix,
  82. )
  83. if spatial is True:
  84. self.m_mapcalc = pymod.Module("r.mapcalc", region="union", run_=False)
  85. else:
  86. self.m_mapcalc = pymod.Module("r.mapcalc")
  87. self.m_mremove = pymod.Module("g.remove")
  88. def parse(self, expression, basename=None, overwrite=False):
  89. # Check for space time dataset type definitions from temporal algebra
  90. l = TemporalRasterAlgebraLexer()
  91. l.build()
  92. l.lexer.input(expression)
  93. while True:
  94. tok = l.lexer.token()
  95. if not tok:
  96. break
  97. if tok.type == "STVDS" or tok.type == "STRDS" or tok.type == "STR3DS":
  98. raise SyntaxError("Syntax error near '%s'" % (tok.type))
  99. self.lexer = TemporalRasterAlgebraLexer()
  100. self.lexer.build()
  101. self.parser = yacc.yacc(module=self, debug=self.debug, write_tables=False)
  102. self.overwrite = overwrite
  103. self.count = 0
  104. self.stdstype = "strds"
  105. self.maptype = "raster"
  106. self.mapclass = RasterDataset
  107. self.basename = basename
  108. self.expression = expression
  109. self.parser.parse(expression)
  110. return self.process_chain_dict
  111. def p_statement_assign(self, t):
  112. # The expression should always return a list of maps.
  113. """
  114. statement : stds EQUALS expr
  115. """
  116. TemporalRasterBaseAlgebraParser.p_statement_assign(self, t)
  117. def p_ts_neighbour_operation(self, t):
  118. # Spatial and temporal neighbour operations via indexing
  119. # Examples:
  120. # A[1,0]
  121. # B[-2]
  122. # C[-2,1,3]
  123. """
  124. expr : stds L_SPAREN number COMMA number R_SPAREN
  125. | stds L_SPAREN number R_SPAREN
  126. | stds L_SPAREN number COMMA number COMMA number R_SPAREN
  127. """
  128. # Check input stds.
  129. maplist = self.check_stds(t[1])
  130. row_neigbour = None
  131. col_neigbour = None
  132. if len(t) == 5:
  133. t_neighbour = t[3]
  134. elif len(t) == 7:
  135. t_neighbour = 0
  136. row_neigbour = t[3]
  137. col_neigbour = t[5]
  138. elif len(t) == 9:
  139. t_neighbour = t[7]
  140. row_neigbour = t[3]
  141. col_neigbour = t[5]
  142. if self.run:
  143. resultlist = []
  144. max_index = len(maplist)
  145. for map_i in maplist:
  146. # Get map index and temporal extent.
  147. map_index = maplist.index(map_i)
  148. new_index = map_index + t_neighbour
  149. if new_index < max_index and new_index >= 0:
  150. map_i_t_extent = map_i.get_temporal_extent()
  151. # Get neighbouring map and set temporal extent.
  152. map_n = maplist[new_index]
  153. # Generate an intermediate map for the result map list.
  154. map_new = self.generate_new_map(map_n, bool_op="and", copy=True)
  155. map_new.set_temporal_extent(map_i_t_extent)
  156. # Create r.mapcalc expression string for the operation.
  157. if "cmd_list" in dir(map_new) and len(t) == 5:
  158. cmdstring = "%s" % (map_new.cmd_list)
  159. elif "cmd_list" not in dir(map_new) and len(t) == 5:
  160. cmdstring = "%s" % (map_n.get_id())
  161. elif "cmd_list" in dir(map_new) and len(t) in (7, 9):
  162. cmdstring = "%s[%s,%s]" % (
  163. map_new.cmd_list,
  164. row_neigbour,
  165. col_neigbour,
  166. )
  167. elif "cmd_list" not in dir(map_new) and len(t) in (7, 9):
  168. cmdstring = "%s[%s,%s]" % (
  169. map_n.get_id(),
  170. row_neigbour,
  171. col_neigbour,
  172. )
  173. # Set new command list for map.
  174. map_new.cmd_list = cmdstring
  175. # Append map with updated command list to result list.
  176. resultlist.append(map_new)
  177. t[0] = resultlist
  178. if __name__ == "__main__":
  179. import doctest
  180. doctest.testmod()