space_time_datasets_tools.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in Python scripts.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. tgis.register_maps_in_space_time_dataset(type, name, 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 space_time_datasets import *
  17. ###############################################################################
  18. def register_maps_in_space_time_dataset(type, name, maps, start=None, increment=None, dbif = None, interval=False):
  19. """Use this method to register maps in space time datasets. This function is generic and
  20. can handle raster, vector and raster3d maps as well as there space time datasets.
  21. Additionally a start time string and an increment string can be specified
  22. to assign a time interval automatically to the maps.
  23. It takes care of the correct update of the space time datasets from all
  24. registered maps.
  25. @param type: The type of the maps raster, raster3d or vector
  26. @param name: The name of the space time dataset
  27. @param maps: A comma separated list of map names
  28. @param start: The start date and time of the first raster map, in case the map has no date (format absolute: "yyyy-mm-dd HH:MM:SS" or "yyyy-mm-dd", format relative 5.0)
  29. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  30. @param dbif: The database interface to be used
  31. @param interval: If True, time intervals are created in case the start time and an increment is provided
  32. """
  33. # We may need the mapset
  34. mapset = core.gisenv()["MAPSET"]
  35. # Check if the dataset name contains the mapset as well
  36. if name.find("@") < 0:
  37. id = name + "@" + mapset
  38. else:
  39. id = name
  40. if type == "raster":
  41. sp = space_time_raster_dataset(id)
  42. if type == "raster3d":
  43. sp = space_time_raster3d_dataset(id)
  44. if type == "vector":
  45. sp = space_time_vector_dataset(id)
  46. connect = False
  47. if dbif == None:
  48. dbif = sql_database_interface()
  49. dbif.connect()
  50. connect = True
  51. # Read content from temporal database
  52. sp.select(dbif)
  53. if sp.is_in_db(dbif) == False:
  54. dbif.close()
  55. core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
  56. if maps.find(",") == -1:
  57. maplist = (maps,)
  58. else:
  59. maplist = tuple(maps.split(","))
  60. num_maps = len(maplist)
  61. count = 0
  62. for mapname in maplist:
  63. core.percent(count, num_maps, 1)
  64. mapname = mapname.strip()
  65. # Check if the map name contains the mapset as well
  66. if mapname.find("@") < 0:
  67. mapid = mapname + "@" + mapset
  68. else:
  69. mapid = mapname
  70. # Get a new instance of the space time dataset map type
  71. map = sp.get_new_map_instance(mapid)
  72. # In case the map is already registered print a message and continue to the next map
  73. # Put the map into the database
  74. if map.is_in_db(dbif) == False:
  75. # Break in case no valid time is provided
  76. if start == "" or start == None:
  77. dbif.close()
  78. core.fatal("Unable to register " + map.get_type() + " map <" + map.get_id() + ">. The map has no valid time and the start time is not set.")
  79. # Load the data from the grass file database
  80. map.load()
  81. if sp.get_temporal_type() == "absolute":
  82. map.set_time_to_absolute()
  83. else:
  84. map.set_time_to_relative()
  85. # Put it into the temporal database
  86. map.insert(dbif)
  87. else:
  88. map.select(dbif)
  89. if map.get_temporal_type() != sp.get_temporal_type():
  90. dbif.close()
  91. core.fatal("Unable to register " + map.get_type() + " map <" + map.get_id() + ">. The temporal types are different.")
  92. # Set the valid time
  93. if start:
  94. assign_valid_time_to_map(ttype=sp.get_temporal_type(), map=map, start=start, end=None, increment=increment, mult=count, dbif=dbif, interval=interval)
  95. # Finally Register map in the space time dataset
  96. sp.register_map(map, dbif)
  97. count += 1
  98. # Update the space time tables
  99. sp.update_from_registered_maps(dbif)
  100. if connect == True:
  101. dbif.close()
  102. core.percent(num_maps, num_maps, 1)
  103. ###############################################################################
  104. def unregister_maps_from_space_time_datasets(type, name, maps, dbif = None):
  105. """Unregister maps from a single space time dataset or, in case no dataset name is provided,
  106. unregister from all datasets within the maps are registered.
  107. @param type: The type of the maps raster, vector or raster3d
  108. @param name: Name of an existing space time raster dataset. If no name is provided the raster map(s) are unregistered from all space time datasets in which they are registered.
  109. @param maps: A comma separated list of map names
  110. @param dbif: The database interface to be used
  111. """
  112. mapset = core.gisenv()["MAPSET"]
  113. if dbif == None:
  114. dbif = sql_database_interface()
  115. dbif.connect()
  116. connect = True
  117. # In case a space time dataset is specified
  118. if name:
  119. # Check if the dataset name contains the mapset as well
  120. if name.find("@") < 0:
  121. id = name + "@" + mapset
  122. else:
  123. id = name
  124. if type == "raster":
  125. sp = space_time_raster_dataset(id)
  126. if type == "raster3d":
  127. sp = space_time_raster3d_dataset(id)
  128. if type == "vector":
  129. sp = space_time_vector_dataset(id)
  130. if sp.is_in_db(dbif) == False:
  131. dbif.close()
  132. core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
  133. # Build the list of maps
  134. if maps.find(",") == -1:
  135. maplist = (maps,)
  136. else:
  137. maplist = tuple(maps.split(","))
  138. num_maps = len(maplist)
  139. count = 0
  140. for mapname in maplist:
  141. core.percent(count, num_maps, 1)
  142. mapname = mapname.strip()
  143. # Check if the map name contains the mapset as well
  144. if mapname.find("@") < 0:
  145. mapid = mapname + "@" + mapset
  146. else:
  147. mapid = mapname
  148. # Create a new instance with the map type
  149. if type == "raster":
  150. map = raster_dataset(mapid)
  151. if type == "raster3d":
  152. map = raster3d_dataset(mapid)
  153. if type == "vector":
  154. map = vector_dataset(mapid)
  155. # Unregister map if in database
  156. if map.is_in_db(dbif) == True:
  157. if name:
  158. sp.select(dbif)
  159. sp.unregister_map(map, dbif)
  160. else:
  161. map.select(dbif)
  162. map.unregister(dbif)
  163. count += 1
  164. if name:
  165. sp.update_from_registered_maps(dbif)
  166. if connect == True:
  167. dbif.close()
  168. core.percent(num_maps, num_maps, 1)
  169. ###############################################################################
  170. def assign_valid_time_to_maps(type, maps, ttype, start, end=None, increment=None, dbif = None, interval=False):
  171. """Use this method to assign valid time (absolute or relative) to raster,
  172. raster3d and vector datasets.
  173. It takes care of the correct update of the space time datasets from all
  174. registered maps.
  175. Valid end time and increment are mutual exclusive.
  176. @param type: The type of the maps raster, raster3d or vector
  177. @param maps: A comma separated list of map names
  178. @param start: The start date and time of the first raster map (format absolute: "yyyy-mm-dd HH:MM:SS" or "yyyy-mm-dd", format relative 5.0)
  179. @param end: The end date and time of the first raster map (format absolute: "yyyy-mm-dd HH:MM:SS" or "yyyy-mm-dd", format relative 5.0)
  180. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  181. @param dbif: The database interface to be used
  182. @param interval: If True, time intervals are created in case the start time and an increment is provided
  183. """
  184. if end and increment:
  185. if dbif:
  186. dbif.close()
  187. core.fatal(_("Valid end time and increment are mutual exclusive"))
  188. # List of space time datasets to be updated
  189. splist = {}
  190. # We may need the mapset
  191. mapset = core.gisenv()["MAPSET"]
  192. if dbif == None:
  193. dbif = sql_database_interface()
  194. dbif.connect()
  195. connect = True
  196. if maps.find(",") == -1:
  197. maplist = (maps,)
  198. else:
  199. maplist = tuple(maps.split(","))
  200. num_maps = len(maplist)
  201. count = 0
  202. for mapname in maplist:
  203. core.percent(count, num_maps, 1)
  204. mapname = mapname.strip()
  205. # Check if the map name contains the mapset as well
  206. if mapname.find("@") < 0:
  207. mapid = mapname + "@" + mapset
  208. else:
  209. mapid = mapname
  210. if type == "raster":
  211. map = raster_dataset(mapid)
  212. if type == "raster3d":
  213. map = raster3d_dataset(mapid)
  214. if type == "vector":
  215. map = vector_dataset(mapid)
  216. if map.is_in_db(dbif) == False:
  217. # Load the data from the grass file database
  218. map.load()
  219. if ttype == "absolute":
  220. map.set_time_to_absolute()
  221. else:
  222. map.set_time_to_relative()
  223. # Put it into the temporal database
  224. map.insert(dbif)
  225. else:
  226. map.select(dbif)
  227. sprows = map.get_registered_datasets(dbif)
  228. # Make an entry in the dataset list, using a dict make sure that
  229. # each dataset is listed only once
  230. if sprows != None:
  231. for dataset in sprows:
  232. splist[dataset["id"]] = True
  233. # Set the valid time
  234. assign_valid_time_to_map(ttype=ttype, map=map, start=start, end=end, increment=increment, mult=count, dbif=dbif, interval=interval)
  235. count += 1
  236. # Update all the space time datasets in which registered maps are changed there valid time
  237. for name in splist.keys():
  238. sp = map.get_new_stds_instance(name)
  239. sp.select(dbif)
  240. sp.update_from_registered_maps(dbif)
  241. if connect == True:
  242. dbif.close()
  243. core.percent(num_maps, num_maps, 1)
  244. ###############################################################################
  245. def assign_valid_time_to_map(ttype, map, start, end, increment=None, mult=1, dbif = None, interval=False):
  246. """Assign the valid time to a map dataset
  247. @param ttype: The temporal type which should be assigned and which the time format is of
  248. @param map: A map dataset object derived from abstract_map_dataset
  249. @param start: The start date and time of the first raster map (format absolute: "yyyy-mm-dd HH:MM:SS" or "yyyy-mm-dd", format relative 5.0)
  250. @param end: The end date and time of the first raster map (format absolute: "yyyy-mm-dd HH:MM:SS" or "yyyy-mm-dd", format relative 5.0)
  251. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  252. @param multi: A multiplier for the increment
  253. @param dbif: The database interface to use for sql queries
  254. @param interval: If True, time intervals are created in case the start time and an increment is provided
  255. """
  256. connect = False
  257. if dbif == None:
  258. dbif = sql_database_interface()
  259. dbif.connect()
  260. connect = True
  261. if ttype == "absolute":
  262. # Create the start time object
  263. if start.find(":") > 0:
  264. time_format = "%Y-%m-%d %H:%M:%S"
  265. else:
  266. time_format = "%Y-%m-%d"
  267. start_time = datetime.strptime(start, time_format)
  268. end_time = None
  269. if end:
  270. end_time = datetime.strptime(end, time_format)
  271. # Add the increment
  272. if increment:
  273. start_time = increment_datetime_by_string(start_time, increment, mult)
  274. if interval:
  275. end_time = increment_datetime_by_string(start_time, increment, 1)
  276. core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_id(), str(start_time), str(end_time)))
  277. map.update_absolute_time(start_time, end_time, None, dbif)
  278. else:
  279. start_time = float(start)
  280. end_time = None
  281. if end:
  282. end_time = float(end)
  283. if increment:
  284. start_time = start_time + mult * float(increment)
  285. if interval:
  286. end_time = start_time + float(increment)
  287. core.verbose(_("Set relative valid time for map <%s> to %f - %s") % (map.get_id(), start_time, str(end_time)))
  288. map.update_relative_time(start_time, end_time, dbif)
  289. if connect == True:
  290. dbif.close()