temporal_granularity.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in temporal GIS Python library package.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. tgis.compute_relative_time_granularity(maps)
  8. ...
  9. @endcode
  10. (C) 2008-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Soeren Gebbert
  15. """
  16. from abstract_dataset import *
  17. from datetime_math import *
  18. ###############################################################################
  19. def check_granularity_string(granularity, temporal_type):
  20. """!Check if the granularity string is valid
  21. @param granularity The granularity string
  22. @param temporal_type The temporal type of the granularity relative or absolute
  23. @return True if valid, False if invalid
  24. """
  25. temporal_type
  26. if granularity is None:
  27. return False
  28. if temporal_type == "absolute":
  29. num, unit = granularity.split(" ")
  30. if unit not in ["second", "seconds", "minute", "minutes", "hour",
  31. "hours", "day", "days", "week", "weeks", "month",
  32. "months", "year", "years"]:
  33. return False
  34. try:
  35. integer = int(num)
  36. except:
  37. return False
  38. elif temporal_type == "relative":
  39. try:
  40. integer = int(granularity)
  41. except:
  42. return False
  43. else:
  44. return False
  45. return True
  46. ###############################################################################
  47. def compute_relative_time_granularity(maps):
  48. """!Compute the relative time granularity
  49. Attention: The computation of the granularity
  50. is only correct in case of not overlapping intervals.
  51. Hence a correct temporal topology is required for computation.
  52. @param maps: a ordered by start_time list of map objects
  53. @return An integer
  54. """
  55. # The interval time must be scaled to days resolution
  56. granularity = None
  57. delta = []
  58. # First we compute the timedelta of the intervals
  59. for map in maps:
  60. start, end = map.get_valid_time()
  61. if start and end:
  62. t = abs(end - start)
  63. delta.append(int(t))
  64. # Compute the timedelta of the gaps
  65. for i in range(len(maps)):
  66. if i < len(maps) - 1:
  67. relation = maps[i + 1].temporal_relation(maps[i])
  68. if relation == "after":
  69. start1, end1 = maps[i].get_valid_time()
  70. start2, end2 = maps[i + 1].get_valid_time()
  71. # Gaps are between intervals, intervals and
  72. # points, points and points
  73. if end1 and start2:
  74. t = abs(end1 - start2)
  75. delta.append(int(t))
  76. if not end1 and start2:
  77. t = abs(start1 - start2)
  78. delta.append(int(t))
  79. delta.sort()
  80. ulist = list(set(delta))
  81. if len(ulist) > 1:
  82. # Find greatest common divisor
  83. granularity = gcd_list(ulist)
  84. elif len(ulist) == 1:
  85. granularity = ulist[0]
  86. else:
  87. granularity = 0
  88. return granularity
  89. ###############################################################################
  90. def compute_absolute_time_granularity(maps):
  91. """!Compute the absolute time granularity
  92. Attention: The computation of the granularity
  93. is only correct in case of not overlapping intervals.
  94. Hence a correct temporal topology is required for computation.
  95. The computed granularity is returned as number of seconds or minutes or hours
  96. or days or months or years.
  97. @param maps: a ordered by start_time list of map objects
  98. @return The temporal topology as string "integer unit"
  99. """
  100. has_seconds = False
  101. has_minutes = False
  102. has_hours = False
  103. has_days = False
  104. has_months = False
  105. has_years = False
  106. use_seconds = False
  107. use_minutes = False
  108. use_hours = False
  109. use_days = False
  110. use_months = False
  111. use_years = False
  112. delta = []
  113. datetime_delta = []
  114. # First we compute the timedelta of the intervals
  115. for map in maps:
  116. start, end = map.get_valid_time()
  117. if start and end:
  118. delta.append(end - start)
  119. datetime_delta.append(compute_datetime_delta(start, end))
  120. # Compute the timedelta of the gaps
  121. for i in range(len(maps)):
  122. if i < len(maps) - 1:
  123. relation = maps[i + 1].temporal_relation(maps[i])
  124. if relation == "after":
  125. start1, end1 = maps[i].get_valid_time()
  126. start2, end2 = maps[i + 1].get_valid_time()
  127. # Gaps are between intervals, intervals and
  128. # points, points and points
  129. if end1 and start2:
  130. delta.append(end1 - start2)
  131. datetime_delta.append(compute_datetime_delta(end1, start2))
  132. if not end1 and start2:
  133. delta.append(start2 - start1)
  134. datetime_delta.append(compute_datetime_delta(
  135. start1, start2))
  136. # Check what changed
  137. dlist = []
  138. for d in datetime_delta:
  139. if "second" in d and d["second"] > 0:
  140. has_seconds = True
  141. if "minute" in d and d["minute"] > 0:
  142. has_minutes = True
  143. if "hour" in d and d["hour"] > 0:
  144. has_hours = True
  145. if "day" in d and d["day"] > 0:
  146. has_days = True
  147. if "month" in d and d["month"] > 0:
  148. has_months = True
  149. if "year" in d and d["year"] > 0:
  150. has_years = True
  151. # Create a list with a single time unit only
  152. if has_seconds:
  153. for d in datetime_delta:
  154. if "second" in d:
  155. dlist.append(d["second"])
  156. elif "minute" in d:
  157. dlist.append(d["minute"] * 60)
  158. elif "hour" in d:
  159. dlist.append(d["hour"] * 3600)
  160. elif "day" in d:
  161. dlist.append(d["day"] * 24 * 3600)
  162. else:
  163. dlist.append(d["max_days"] * 24 * 3600)
  164. use_seconds = True
  165. elif has_minutes:
  166. for d in datetime_delta:
  167. if "minute" in d:
  168. dlist.append(d["minute"])
  169. elif "hour" in d:
  170. dlist.append(d["hour"] * 60)
  171. elif "day" in d:
  172. dlist.append(d["day"] * 24 * 60)
  173. else:
  174. dlist.append(d["max_days"] * 24 * 60)
  175. use_minutes = True
  176. elif has_hours:
  177. for d in datetime_delta:
  178. if "hour" in d:
  179. dlist.append(d["hour"])
  180. elif "day" in d:
  181. dlist.append(d["day"] * 24)
  182. else:
  183. dlist.append(d["max_days"] * 24)
  184. use_hours = True
  185. elif has_days:
  186. for d in datetime_delta:
  187. if "day" in d:
  188. dlist.append(d["day"])
  189. else:
  190. dlist.append(d["max_days"])
  191. use_days = True
  192. elif has_months:
  193. for d in datetime_delta:
  194. if "month" in d:
  195. dlist.append(d["month"])
  196. elif "year" in d:
  197. dlist.append(d["year"] * 12)
  198. use_months = True
  199. elif has_years:
  200. for d in datetime_delta:
  201. if "year" in d:
  202. dlist.append(d["year"])
  203. use_years = True
  204. dlist.sort()
  205. ulist = list(set(dlist))
  206. if len(ulist) == 0:
  207. return None
  208. if len(ulist) > 1:
  209. # Find greatest common divisor
  210. granularity = gcd_list(ulist)
  211. else:
  212. granularity = ulist[0]
  213. if use_seconds:
  214. if granularity == 1:
  215. return "%i second" % granularity
  216. else:
  217. return "%i seconds" % granularity
  218. elif use_minutes:
  219. if granularity == 1:
  220. return "%i minute" % granularity
  221. else:
  222. return "%i minutes" % granularity
  223. elif use_hours:
  224. if granularity == 1:
  225. return "%i hour" % granularity
  226. else:
  227. return "%i hours" % granularity
  228. elif use_days:
  229. if granularity == 1:
  230. return "%i day" % granularity
  231. else:
  232. return "%i days" % granularity
  233. elif use_months:
  234. if granularity == 1:
  235. return "%i month" % granularity
  236. else:
  237. return "%i months" % granularity
  238. elif use_years:
  239. if granularity == 1:
  240. return "%i year" % granularity
  241. else:
  242. return "%i years" % granularity
  243. return None
  244. ###############################################################################
  245. # http://akiscode.com/articles/gcd_of_a_list.shtml
  246. # Copyright (c) 2010 Stephen Akiki
  247. # MIT License (Means you can do whatever you want with this)
  248. # See http://www.opensource.org/licenses/mit-license.php
  249. # Error Codes:
  250. # None
  251. def gcd(a, b):
  252. """!The Euclidean Algorithm """
  253. a = abs(a)
  254. b = abs(b)
  255. while a:
  256. a, b = b % a, a
  257. return b
  258. ###############################################################################
  259. def gcd_list(list):
  260. """!Finds the GCD of numbers in a list.
  261. Input: List of numbers you want to find the GCD of
  262. E.g. [8, 24, 12]
  263. Returns: GCD of all numbers
  264. """
  265. return reduce(gcd, list)