temporal_granularity.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 compute_relative_time_granularity(maps):
  20. """!Compute the relative time granularity
  21. Attention: The computation of the granularity
  22. is only correct in case of not overlapping intervals.
  23. Hence a correct temporal topology is required for computation.
  24. @param maps: a ordered by start_time list of map objects
  25. @return An integer
  26. """
  27. # The interval time must be scaled to days resolution
  28. granularity = None
  29. delta = []
  30. # First we compute the timedelta of the intervals
  31. for map in maps:
  32. start, end = map.get_valid_time()
  33. if start and end:
  34. t = abs(end - start)
  35. delta.append(int(t))
  36. # Compute the timedelta of the gaps
  37. for i in range(len(maps)):
  38. if i < len(maps) - 1:
  39. relation = maps[i + 1].temporal_relation(maps[i])
  40. if relation == "after":
  41. start1, end1 = maps[i].get_valid_time()
  42. start2, end2 = maps[i + 1].get_valid_time()
  43. # Gaps are between intervals, intervals and
  44. # points, points and points
  45. if end1 and start2:
  46. t = abs(end1 - start2)
  47. delta.append(int(t))
  48. if not end1 and start2:
  49. t = abs(start1 - start2)
  50. delta.append(int(t))
  51. delta.sort()
  52. ulist = list(set(delta))
  53. if len(ulist) > 1:
  54. # Find greatest common divisor
  55. granularity = gcd_list(ulist)
  56. elif len(ulist) == 1:
  57. granularity = ulist[0]
  58. else:
  59. granularity = 0
  60. return granularity
  61. ###############################################################################
  62. def compute_absolute_time_granularity(maps):
  63. """!Compute the absolute time granularity
  64. Attention: The computation of the granularity
  65. is only correct in case of not overlapping intervals.
  66. Hence a correct temporal topology is required for computation.
  67. The computed granularity is returned as number of seconds or minutes or hours
  68. or days or months or years.
  69. @param maps: a ordered by start_time list of map objects
  70. @return The temporal topology as string "integer unit"
  71. """
  72. has_seconds = False
  73. has_minutes = False
  74. has_hours = False
  75. has_days = False
  76. has_months = False
  77. has_years = False
  78. use_seconds = False
  79. use_minutes = False
  80. use_hours = False
  81. use_days = False
  82. use_months = False
  83. use_years = False
  84. delta = []
  85. datetime_delta = []
  86. # First we compute the timedelta of the intervals
  87. for map in maps:
  88. start, end = map.get_valid_time()
  89. if start and end:
  90. delta.append(end - start)
  91. datetime_delta.append(compute_datetime_delta(start, end))
  92. # Compute the timedelta of the gaps
  93. for i in range(len(maps)):
  94. if i < len(maps) - 1:
  95. relation = maps[i + 1].temporal_relation(maps[i])
  96. if relation == "after":
  97. start1, end1 = maps[i].get_valid_time()
  98. start2, end2 = maps[i + 1].get_valid_time()
  99. # Gaps are between intervals, intervals and
  100. # points, points and points
  101. if end1 and start2:
  102. delta.append(end1 - start2)
  103. datetime_delta.append(compute_datetime_delta(end1, start2))
  104. if not end1 and start2:
  105. delta.append(start2 - start1)
  106. datetime_delta.append(compute_datetime_delta(
  107. start1, start2))
  108. # Check what changed
  109. dlist = []
  110. for d in datetime_delta:
  111. if "second" in d and d["second"] > 0:
  112. has_seconds = True
  113. if "minute" in d and d["minute"] > 0:
  114. has_minutes = True
  115. if "hour" in d and d["hour"] > 0:
  116. has_hours = True
  117. if "day" in d and d["day"] > 0:
  118. has_days = True
  119. if "month" in d and d["month"] > 0:
  120. has_months = True
  121. if "year" in d and d["year"] > 0:
  122. has_years = True
  123. # Create a list with a single time unit only
  124. if has_seconds:
  125. for d in datetime_delta:
  126. if "second" in d:
  127. dlist.append(d["second"])
  128. elif "minute" in d:
  129. dlist.append(d["minute"] * 60)
  130. elif "hour" in d:
  131. dlist.append(d["hour"] * 3600)
  132. elif "day" in d:
  133. dlist.append(d["day"] * 24 * 3600)
  134. else:
  135. dlist.append(d["max_days"] * 24 * 3600)
  136. use_seconds = True
  137. elif has_minutes:
  138. for d in datetime_delta:
  139. if "minute" in d:
  140. dlist.append(d["minute"])
  141. elif "hour" in d:
  142. dlist.append(d["hour"] * 60)
  143. elif "day" in d:
  144. dlist.append(d["day"] * 24 * 60)
  145. else:
  146. dlist.append(d["max_days"] * 24 * 60)
  147. use_minutes = True
  148. elif has_hours:
  149. for d in datetime_delta:
  150. if "hour" in d:
  151. dlist.append(d["hour"])
  152. elif "day" in d:
  153. dlist.append(d["day"] * 24)
  154. else:
  155. dlist.append(d["max_days"] * 24)
  156. use_hours = True
  157. elif has_days:
  158. for d in datetime_delta:
  159. if "day" in d:
  160. dlist.append(d["day"])
  161. else:
  162. dlist.append(d["max_days"])
  163. use_days = True
  164. elif has_months:
  165. for d in datetime_delta:
  166. if "month" in d:
  167. dlist.append(d["month"])
  168. elif "year" in d:
  169. dlist.append(d["year"] * 12)
  170. use_months = True
  171. elif has_years:
  172. for d in datetime_delta:
  173. if "year" in d:
  174. dlist.append(d["year"])
  175. use_years = True
  176. dlist.sort()
  177. ulist = list(set(dlist))
  178. if len(ulist) == 0:
  179. return None
  180. if len(ulist) > 1:
  181. # Find greatest common divisor
  182. granularity = gcd_list(ulist)
  183. else:
  184. granularity = ulist[0]
  185. if use_seconds:
  186. return "%i seconds" % granularity
  187. elif use_minutes:
  188. return "%i minutes" % granularity
  189. elif use_hours:
  190. return "%i hours" % granularity
  191. elif use_days:
  192. return "%i days" % granularity
  193. elif use_months:
  194. return "%i months" % granularity
  195. elif use_years:
  196. return "%i years" % granularity
  197. return None
  198. ###############################################################################
  199. # http://akiscode.com/articles/gcd_of_a_list.shtml
  200. # Copyright (c) 2010 Stephen Akiki
  201. # MIT License (Means you can do whatever you want with this)
  202. # See http://www.opensource.org/licenses/mit-license.php
  203. # Error Codes:
  204. # None
  205. def gcd(a, b):
  206. """!The Euclidean Algorithm """
  207. a = abs(a)
  208. b = abs(b)
  209. while a:
  210. a, b = b % a, a
  211. return b
  212. ###############################################################################
  213. def gcd_list(list):
  214. """!Finds the GCD of numbers in a list.
  215. Input: List of numbers you want to find the GCD of
  216. E.g. [8, 24, 12]
  217. Returns: GCD of all numbers
  218. """
  219. return reduce(gcd, list)