space_time_datasets_tools.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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=None, file=None, start=None, end=None, increment=None, dbif = None, interval=False, fs="|"):
  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 file: Input file one map with optional start and end time, one per line
  29. @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)
  30. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  31. @param dbif: The database interface to be used
  32. @param interval: If True, time intervals are created in case the start time and an increment is provided
  33. @param fs: Field separator used in input file
  34. """
  35. start_time_in_file = False
  36. end_time_in_file = False
  37. if maps and file:
  38. core.fata(_("%s= and %s= are mutually exclusive") % ("input","file"))
  39. if end and increment:
  40. core.fata(_("%s= and %s= are mutually exclusive") % ("end","increment"))
  41. if end and not start:
  42. core.fata(_("Please specify %s= and %s=") % ("start_time","end_time"))
  43. if not maps and not file:
  44. core.fata(_("Please specify %s= or %s=") % ("input","file"))
  45. if start and start == "file":
  46. start_time_in_file = True
  47. if end and end == "file":
  48. end_time_in_file = True
  49. # We may need the mapset
  50. mapset = core.gisenv()["MAPSET"]
  51. # Check if the dataset name contains the mapset as well
  52. if name.find("@") < 0:
  53. id = name + "@" + mapset
  54. else:
  55. id = name
  56. sp = dataset_factory(type, id)
  57. connect = False
  58. if dbif == None:
  59. dbif = sql_database_interface()
  60. dbif.connect()
  61. connect = True
  62. # Read content from temporal database
  63. sp.select(dbif)
  64. if sp.is_in_db(dbif) == False:
  65. dbif.close()
  66. core.fatal(_("Space time %s dataset <%s> no found") % (sp.get_new_map_instance(None).get_type(). name))
  67. maplist = []
  68. # Map names as comma separated string
  69. if maps:
  70. if maps.find(",") == -1:
  71. maplist = (maps,)
  72. else:
  73. maplist = tuple(maps.split(","))
  74. # Read the map list from file
  75. if file:
  76. fd = open(file, "r")
  77. line = True
  78. while True:
  79. line = fd.readline()
  80. if not line:
  81. break
  82. line_list = line.split(fs)
  83. mapname = line_list[0].strip()
  84. if mapname.find("@") < 0:
  85. mapid = mapname + "@" + mapset
  86. else:
  87. mapid = mapname
  88. row = {}
  89. row["id"] = mapid
  90. if start_time_in_file and end_time_in_file:
  91. row["start"] = line_list[1].strip()
  92. row["end"] = line_list[2].strip()
  93. if start_time_in_file and not end_time_in_file:
  94. row["start"] = line_list[1].strip()
  95. maplist.append(row)
  96. num_maps = len(maplist)
  97. count = 0
  98. for entry in maplist:
  99. core.percent(count, num_maps, 1)
  100. # Get a new instance of the space time dataset map type
  101. if file:
  102. map = sp.get_new_map_instance(entry["id"])
  103. else:
  104. if entry.find("@") < 0:
  105. mapid = entry + "@" + mapset
  106. else:
  107. mapid = entry
  108. map = sp.get_new_map_instance(mapid)
  109. # Use the time data from file
  110. if start_time_in_file:
  111. start = entry["start"]
  112. if end_time_in_file:
  113. end = entry["end"]
  114. # Put the map into the database
  115. if map.is_in_db(dbif) == False:
  116. # Break in case no valid time is provided
  117. if start == "" or start == None:
  118. dbif.close()
  119. core.fatal(_("Unable to register %s map <%s>. The map has no valid time and the start time is not set.") % \
  120. (map.get_type(), map.get_id() ))
  121. # Load the data from the grass file database
  122. map.load()
  123. if sp.get_temporal_type() == "absolute":
  124. map.set_time_to_absolute()
  125. else:
  126. map.set_time_to_relative()
  127. # Put it into the temporal database
  128. map.insert(dbif)
  129. else:
  130. map.select(dbif)
  131. if map.get_temporal_type() != sp.get_temporal_type():
  132. dbif.close()
  133. core.fatal(_("Unable to register %s map <%s>. The temporal types are different.") % (map.get_type(), map.get_id()))
  134. # In case the time is in the input file we ignore the increment counter
  135. if start_time_in_file:
  136. count = 1
  137. # Set the valid time
  138. if start:
  139. assign_valid_time_to_map(ttype=sp.get_temporal_type(), map=map, start=start, end=end, increment=increment, mult=count, dbif=dbif, interval=interval)
  140. # Finally Register map in the space time dataset
  141. sp.register_map(map, dbif)
  142. count += 1
  143. # Update the space time tables
  144. sp.update_from_registered_maps(dbif)
  145. if connect == True:
  146. dbif.close()
  147. core.percent(num_maps, num_maps, 1)
  148. ###############################################################################
  149. def unregister_maps_from_space_time_datasets(type, name, maps, file=None, dbif = None):
  150. """Unregister maps from a single space time dataset or, in case no dataset name is provided,
  151. unregister from all datasets within the maps are registered.
  152. @param type: The type of the maps raster, vector or raster3d
  153. @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.
  154. @param maps: A comma separated list of map names
  155. @param dbif: The database interface to be used
  156. """
  157. if maps and file:
  158. core.fata(_("%s= and %s= are mutually exclusive") % ("input","file"))
  159. mapset = core.gisenv()["MAPSET"]
  160. if dbif == None:
  161. dbif = sql_database_interface()
  162. dbif.connect()
  163. connect = True
  164. # In case a space time dataset is specified
  165. if name:
  166. # Check if the dataset name contains the mapset as well
  167. if name.find("@") < 0:
  168. id = name + "@" + mapset
  169. else:
  170. id = name
  171. sp = dataset_factory(type, id)
  172. if sp.is_in_db(dbif) == False:
  173. dbif.close()
  174. core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
  175. maplist = []
  176. # Map names as comma separated string
  177. if maps:
  178. if maps.find(",") == -1:
  179. maplist = (maps,)
  180. else:
  181. maplist = tuple(maps.split(","))
  182. # Read the map list from file
  183. if file:
  184. fd = open(file, "r")
  185. line = True
  186. while True:
  187. line = fd.readline()
  188. if not line:
  189. break
  190. line_list = line.split(fs)
  191. mapname = line_list[0].strip()
  192. maplist.append(mapname)
  193. num_maps = len(maplist)
  194. count = 0
  195. for mapname in maplist:
  196. core.percent(count, num_maps, 1)
  197. mapname = mapname.strip()
  198. # Check if the map name contains the mapset as well
  199. if mapname.find("@") < 0:
  200. mapid = mapname + "@" + mapset
  201. else:
  202. mapid = mapname
  203. # Create a new instance with the map type
  204. if type == "rast":
  205. map = raster_dataset(mapid)
  206. if type == "rast3d":
  207. map = raster3d_dataset(mapid)
  208. if type == "vect":
  209. map = vector_dataset(mapid)
  210. # Unregister map if in database
  211. if map.is_in_db(dbif) == True:
  212. if name:
  213. sp.select(dbif)
  214. sp.unregister_map(map, dbif)
  215. else:
  216. map.select(dbif)
  217. map.unregister(dbif)
  218. count += 1
  219. if name:
  220. sp.update_from_registered_maps(dbif)
  221. if connect == True:
  222. dbif.close()
  223. core.percent(num_maps, num_maps, 1)
  224. ###############################################################################
  225. def assign_valid_time_to_maps(type, maps, ttype, start, end=None, file=file, increment=None, dbif = None, interval=False, fs="|"):
  226. """Use this method to assign valid time (absolute or relative) to raster,
  227. raster3d and vector datasets.
  228. It takes care of the correct update of the space time datasets from all
  229. registered maps.
  230. Valid end time and increment are mutual exclusive.
  231. @param type: The type of the maps raster, raster3d or vector
  232. @param maps: A comma separated list of map names
  233. @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)
  234. @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)
  235. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  236. @param file: Input file one map with optional start and end time, one per line
  237. @param dbif: The database interface to be used
  238. @param interval: If True, time intervals are created in case the start time and an increment is provided
  239. @param fs: Field separator used in input file
  240. """
  241. start_time_in_file = False
  242. end_time_in_file = False
  243. if end and increment:
  244. if dbif:
  245. dbif.close()
  246. core.fatal(_("Valid end time and increment are mutual exclusive"))
  247. # List of space time datasets to be updated
  248. splist = {}
  249. if maps and file:
  250. core.fata(_("%s= and %s= are mutually exclusive") % ("input","file"))
  251. if end and increment:
  252. core.fata(_("%s= and %s= are mutually exclusive") % ("end","increment"))
  253. if end and not start:
  254. core.fata(_("Please specify %s= and %s=") % ("start_time","end_time"))
  255. if not maps and not file:
  256. core.fata(_("Please specify %s= or %s=") % ("input","file"))
  257. if start and start == "file":
  258. start_time_in_file = True
  259. if end and end == "file":
  260. end_time_in_file = True
  261. # We may need the mapset
  262. mapset = core.gisenv()["MAPSET"]
  263. connect = False
  264. if dbif == None:
  265. dbif = sql_database_interface()
  266. dbif.connect()
  267. connect = True
  268. maplist = []
  269. # Map names as comma separated string
  270. if maps:
  271. if maps.find(",") == -1:
  272. maplist = (maps,)
  273. else:
  274. maplist = tuple(maps.split(","))
  275. # Read the map list from file
  276. if file:
  277. fd = open(file, "r")
  278. line = True
  279. while True:
  280. line = fd.readline()
  281. if not line:
  282. break
  283. line_list = line.split(fs)
  284. mapname = line_list[0].strip()
  285. if mapname.find("@") < 0:
  286. mapid = mapname + "@" + mapset
  287. else:
  288. mapid = mapname
  289. row = {}
  290. row["id"] = mapid
  291. if start_time_in_file and end_time_in_file:
  292. row["start"] = line_list[1].strip()
  293. row["end"] = line_list[2].strip()
  294. if start_time_in_file and not end_time_in_file:
  295. row["start"] = line_list[1].strip()
  296. maplist.append(row)
  297. num_maps = len(maplist)
  298. count = 0
  299. for entry in maplist:
  300. core.percent(count, num_maps, 1)
  301. if file:
  302. mapid = entry["id"]
  303. else:
  304. if entry.find("@") < 0:
  305. mapid = entry + "@" + mapset
  306. else:
  307. mapid = entry
  308. sp = dataset_factory(type, id)
  309. # Use the time data from file
  310. if start_time_in_file:
  311. start = entry["start"]
  312. if end_time_in_file:
  313. end = entry["end"]
  314. if map.is_in_db(dbif) == False:
  315. # Load the data from the grass file database
  316. map.load()
  317. if ttype == "absolute":
  318. map.set_time_to_absolute()
  319. else:
  320. map.set_time_to_relative()
  321. # Put it into the temporal database
  322. map.insert(dbif)
  323. else:
  324. map.select(dbif)
  325. sprows = map.get_registered_datasets(dbif)
  326. # Make an entry in the dataset list, using a dict make sure that
  327. # each dataset is listed only once
  328. if sprows != None:
  329. for dataset in sprows:
  330. splist[dataset["id"]] = True
  331. # In case the time is in the input file we ignore the increment counter
  332. if start_time_in_file:
  333. count = 1
  334. # Set the valid time
  335. assign_valid_time_to_map(ttype=ttype, map=map, start=start, end=end, increment=increment, mult=count, dbif=dbif, interval=interval)
  336. count += 1
  337. # Update all the space time datasets in which registered maps are changed there valid time
  338. for name in splist.keys():
  339. sp = map.get_new_stds_instance(name)
  340. sp.select(dbif)
  341. sp.update_from_registered_maps(dbif)
  342. if connect == True:
  343. dbif.close()
  344. core.percent(num_maps, num_maps, 1)
  345. ###############################################################################
  346. def assign_valid_time_to_map(ttype, map, start, end, increment=None, mult=1, dbif = None, interval=False):
  347. """Assign the valid time to a map dataset
  348. @param ttype: The temporal type which should be assigned and which the time format is of
  349. @param map: A map dataset object derived from abstract_map_dataset
  350. @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)
  351. @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)
  352. @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
  353. @param multi: A multiplier for the increment
  354. @param dbif: The database interface to use for sql queries
  355. @param interval: If True, time intervals are created in case the start time and an increment is provided
  356. """
  357. connect = False
  358. if dbif == None:
  359. dbif = sql_database_interface()
  360. dbif.connect()
  361. connect = True
  362. if ttype == "absolute":
  363. # Create the start time object
  364. if start.find(":") > 0:
  365. time_format = "%Y-%m-%d %H:%M:%S"
  366. else:
  367. time_format = "%Y-%m-%d"
  368. start_time = datetime.strptime(start, time_format)
  369. end_time = None
  370. if end:
  371. end_time = datetime.strptime(end, time_format)
  372. # Add the increment
  373. if increment:
  374. start_time = increment_datetime_by_string(start_time, increment, mult)
  375. if interval:
  376. end_time = increment_datetime_by_string(start_time, increment, 1)
  377. core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_id(), str(start_time), str(end_time)))
  378. map.update_absolute_time(start_time, end_time, None, dbif)
  379. else:
  380. start_time = float(start)
  381. end_time = None
  382. if end:
  383. end_time = float(end)
  384. if increment:
  385. start_time = start_time + mult * float(increment)
  386. if interval:
  387. end_time = start_time + float(increment)
  388. core.verbose(_("Set relative valid time for map <%s> to %f - %s") % (map.get_id(), start_time, str(end_time)))
  389. map.update_relative_time(start_time, end_time, dbif)
  390. if connect == True:
  391. dbif.close()
  392. ###############################################################################
  393. def dataset_factory(type, id):
  394. """A factory functions to create space time or map datasets
  395. @param type: the dataset type: rast, rast3d, vect, strds, str3ds, stvds
  396. @param id: The id of the dataset ("name@mapset")
  397. """
  398. print type, id
  399. if type == "strds":
  400. sp = space_time_raster_dataset(id)
  401. elif type == "str3ds":
  402. sp = space_time_raster3d_dataset(id)
  403. elif type == "stvds":
  404. sp = space_time_vector_dataset(id)
  405. elif type == "rast":
  406. sp = raster_dataset(id)
  407. elif type == "rast3d":
  408. sp = raster3d_dataset(id)
  409. elif type == "vect":
  410. sp = vector_dataset(id)
  411. else:
  412. core.error(_("Unknown dataset type: %s") % type)
  413. return None
  414. return sp