stds_import.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. """
  2. Space time dataset import functions
  3. Usage:
  4. .. code-block:: python
  5. import grass.temporal as tgis
  6. input="/tmp/temp_1950_2012.tar.gz"
  7. output="temp_1950_2012"
  8. extrdir="/tmp"
  9. title="My new dataset"
  10. descr="May new shiny dataset"
  11. location=None
  12. link=True
  13. exp=True
  14. overr=False
  15. create=False
  16. tgis.import_stds(input, output, extrdir, title, descr, location,
  17. link, exp, overr, create, "strds")
  18. (C) 2012-2013 by the GRASS Development Team
  19. This program is free software under the GNU General Public
  20. License (>=v2). Read the file COPYING that comes with GRASS
  21. for details.
  22. :authors: Soeren Gebbert
  23. """
  24. import os
  25. import os.path
  26. import tarfile
  27. from space_time_datasets import *
  28. from register import *
  29. import factory
  30. from factory import *
  31. import grass.script as gscript
  32. proj_file_name = "proj.txt"
  33. init_file_name = "init.txt"
  34. list_file_name = "list.txt"
  35. # This global variable is for unique vector map export,
  36. # since single vector maps may have several layer
  37. # and therefore several attribute tables
  38. imported_maps = {}
  39. ############################################################################
  40. def _import_raster_maps_from_gdal(maplist, overr, exp, location, link, format_,
  41. set_current_region=False):
  42. impflags = ""
  43. if overr:
  44. impflags += "o"
  45. if exp or location:
  46. impflags += "e"
  47. for row in maplist:
  48. name = row["name"]
  49. if format_ == "GTiff":
  50. filename = row["filename"] + ".tif"
  51. elif format_=="AAIGrid":
  52. filename = row["filename"] + ".asc"
  53. if not overr:
  54. impflags += "o"
  55. if link:
  56. ret = gscript.run_command("r.external", input=filename,
  57. output=name,
  58. flags=impflags,
  59. overwrite=gscript.overwrite())
  60. else:
  61. ret = gscript.run_command("r.in.gdal", input=filename,
  62. output=name,
  63. flags=impflags,
  64. overwrite=gscript.overwrite())
  65. if ret != 0:
  66. gscript.fatal(_("Unable to import/link raster map <%s> from file %s.") %(name,
  67. filename))
  68. # Set the color rules if present
  69. filename = row["filename"] + ".color"
  70. if os.path.isfile(filename):
  71. ret = gscript.run_command("r.colors", map=name,
  72. rules=filename,
  73. overwrite=gscript.overwrite())
  74. if ret != 0:
  75. gscript.fatal(_("Unable to set the color rules for "
  76. "raster map <%s>.") % name)
  77. # Set the computational region from the last map imported
  78. if set_current_region is True:
  79. gscript.run_command("g.region", rast=name)
  80. ############################################################################
  81. def _import_raster_maps(maplist, set_current_region=False):
  82. # We need to disable the projection check because of its
  83. # simple implementation
  84. impflags = "o"
  85. for row in maplist:
  86. name = row["name"]
  87. filename = row["filename"] + ".pack"
  88. ret = gscript.run_command("r.unpack", input=filename,
  89. output=name,
  90. flags=impflags,
  91. overwrite=gscript.overwrite(),
  92. verbose=True)
  93. if ret != 0:
  94. gscript.fatal(_("Unable to unpack raster map <%s> from file %s.") % (name,
  95. filename))
  96. # Set the computational region from the last map imported
  97. if set_current_region is True:
  98. gscript.run_command("g.region", rast=name)
  99. ############################################################################
  100. def _import_vector_maps_from_gml(maplist, overr, exp, location, link):
  101. impflags = "o"
  102. if exp or location:
  103. impflags += "e"
  104. for row in maplist:
  105. name = row["name"]
  106. filename = row["filename"] + ".xml"
  107. ret = gscript.run_command("v.in.ogr", dsn=filename,
  108. output=name,
  109. flags=impflags,
  110. overwrite=gscript.overwrite())
  111. if ret != 0:
  112. gscript.fatal(_("Unable to import vector map <%s> from file %s.") % (name,
  113. filename))
  114. ############################################################################
  115. def _import_vector_maps(maplist):
  116. # We need to disable the projection check because of its
  117. # simple implementation
  118. impflags = "o"
  119. for row in maplist:
  120. # Separate the name from the layer
  121. name = row["name"].split(":")[0]
  122. # Import only unique maps
  123. if name in imported_maps:
  124. continue
  125. filename = row["filename"] + ".pack"
  126. ret = gscript.run_command("v.unpack", input=filename,
  127. output=name,
  128. flags=impflags,
  129. overwrite=gscript.overwrite(),
  130. verbose=True)
  131. if ret != 0:
  132. gscript.fatal(_("Unable to unpack vector map <%s> from file %s.") % (name,
  133. filename))
  134. imported_maps[name] = name
  135. ############################################################################
  136. def import_stds(input, output, extrdir, title=None, descr=None, location=None,
  137. link=False, exp=False, overr=False, create=False, stds_type="strds",
  138. base=None, set_current_region=False):
  139. """Import space time datasets of type raster and vector
  140. :param input: Name of the input archive file
  141. :param output: The name of the output space time dataset
  142. :param extrdir: The extraction directory
  143. :param title: The title of the new created space time dataset
  144. :param descr: The description of the new created
  145. space time dataset
  146. :param location: The name of the location that should be created,
  147. maps are imported into this location
  148. :param link: Switch to link raster maps instead importing them
  149. :param exp: Extend location extents based on new dataset
  150. :param overr: Override projection (use location's projection)
  151. :param create: Create the location specified by the "location"
  152. parameter and exit.
  153. Do not import the space time datasets.
  154. :param stds_type: The type of the space time dataset that
  155. should be imported
  156. :param base: The base name of the new imported maps, it will be extended
  157. using a numerical index.
  158. """
  159. global raise_on_error
  160. old_state = gscript.raise_on_error
  161. gscript.set_raise_on_error(True)
  162. # Check if input file and extraction directory exits
  163. if not os.path.exists(input):
  164. gscript.fatal(_("Space time raster dataset archive <%s> not found")
  165. % input)
  166. if not create and not os.path.exists(extrdir):
  167. gscript.fatal(_("Extraction directory <%s> not found") % extrdir)
  168. tar = tarfile.open(name=input, mode='r')
  169. # Check for important files
  170. members = tar.getnames()
  171. if init_file_name not in members:
  172. gscript.fatal(_("Unable to find init file <%s>") % init_file_name)
  173. if list_file_name not in members:
  174. gscript.fatal(_("Unable to find list file <%s>") % list_file_name)
  175. if proj_file_name not in members:
  176. gscript.fatal(_("Unable to find projection file <%s>") % proj_file_name)
  177. tar.extractall(path=extrdir)
  178. tar.close()
  179. # We use a new list file name for map registration
  180. new_list_file_name = list_file_name + "_new"
  181. # Save current working directory path
  182. old_cwd = os.getcwd()
  183. # Switch into the data directory
  184. os.chdir(extrdir)
  185. # Check projection information
  186. if not location:
  187. temp_name = gscript.tempfile()
  188. temp_file = open(temp_name, "w")
  189. proj_name = os.path.abspath(proj_file_name)
  190. p = gscript.start_command("g.proj", flags="j", stdout=temp_file)
  191. p.communicate()
  192. temp_file.close()
  193. if not gscript.compare_key_value_text_files(temp_name, proj_name, sep="="):
  194. if overr:
  195. gscript.warning(_("Projection information does not match. "
  196. "Proceeding..."))
  197. else:
  198. diff = ''.join(gscript.diff_files(temp_name, proj_name))
  199. gscript.warning(_("Difference between PROJ_INFO file of imported map "
  200. "and of current location:\n{diff}").format(diff=diff))
  201. gscript.fatal(_("Projection information does not match. Aborting."))
  202. # Create a new location based on the projection information and switch
  203. # into it
  204. old_env = gscript.gisenv()
  205. if location:
  206. try:
  207. proj4_string = open(proj_file_name, 'r').read()
  208. gscript.create_location(dbase=old_env["GISDBASE"],
  209. location=location,
  210. proj4=proj4_string)
  211. # Just create a new location and return
  212. if create:
  213. os.chdir(old_cwd)
  214. return
  215. except Exception as e:
  216. gscript.fatal(_("Unable to create location %(l)s. Reason: %(e)s")
  217. % {'l': location, 'e': str(e)})
  218. # Switch to the new created location
  219. ret = gscript.run_command("g.mapset", mapset="PERMANENT",
  220. location=location,
  221. gisdbase=old_env["GISDBASE"])
  222. if ret != 0:
  223. gscript.fatal(_("Unable to switch to location %s") % location)
  224. # create default database connection
  225. ret = gscript.run_command("t.connect", flags="d")
  226. if ret != 0:
  227. gscript.fatal(_("Unable to create default temporal database "
  228. "in new location %s") % location)
  229. try:
  230. # Make sure the temporal database exists
  231. factory.init()
  232. fs = "|"
  233. maplist = []
  234. mapset = get_current_mapset()
  235. list_file = open(list_file_name, "r")
  236. new_list_file = open(new_list_file_name, "w")
  237. # get number of lines to correctly form the suffix
  238. max_count = -1
  239. for max_count, l in enumerate(list_file):
  240. pass
  241. max_count += 1
  242. list_file.seek(0)
  243. # Read the map list from file
  244. line_count = 0
  245. while True:
  246. line = list_file.readline()
  247. if not line:
  248. break
  249. line_list = line.split(fs)
  250. # The filename is actually the base name of the map
  251. # that must be extended by the file suffix
  252. filename = line_list[0].strip().split(":")[0]
  253. if base:
  254. mapname = "%s_%s" % (base, gscript.get_num_suffix(line_count + 1, max_count))
  255. mapid= "%s@%s"%(mapname, mapset)
  256. else:
  257. mapname = filename
  258. mapid = mapname + "@" + mapset
  259. row = {}
  260. row["filename"] = filename
  261. row["name"] = mapname
  262. row["id"] = mapid
  263. row["start"] = line_list[1].strip()
  264. row["end"] = line_list[2].strip()
  265. new_list_file.write("%s%s%s%s%s\n"%(mapname,fs, row["start"],
  266. fs, row["end"]))
  267. maplist.append(row)
  268. line_count += 1
  269. list_file.close()
  270. new_list_file.close()
  271. # Read the init file
  272. fs = "="
  273. init = {}
  274. init_file = open(init_file_name, "r")
  275. while True:
  276. line = init_file.readline()
  277. if not line:
  278. break
  279. kv = line.split(fs)
  280. init[kv[0]] = kv[1].strip()
  281. init_file.close()
  282. if "temporal_type" not in init or \
  283. "semantic_type" not in init or \
  284. "number_of_maps" not in init:
  285. gscript.fatal(_("Key words %(t)s, %(s)s or %(n)s not found in init"
  286. " file.") % {'t': "temporal_type",
  287. 's': "semantic_type",
  288. 'n': "number_of_maps"})
  289. if line_count != int(init["number_of_maps"]):
  290. gscript.fatal(_("Number of maps mismatch in init and list file."))
  291. format_ = "GTiff"
  292. type_ = "strds"
  293. if "stds_type" in init:
  294. type_ = init["stds_type"]
  295. if "format" in init:
  296. format_ = init["format"]
  297. if stds_type != type_:
  298. gscript.fatal(_("The archive file is of wrong space time dataset type"))
  299. # Check the existence of the files
  300. if format_ == "GTiff":
  301. for row in maplist:
  302. filename = row["filename"] + ".tif"
  303. if not os.path.exists(filename):
  304. gscript.fatal(_("Unable to find GeoTIFF raster file "
  305. "<%s> in archive.") % filename)
  306. elif format_ == "AAIGrid":
  307. for row in maplist:
  308. filename = row["filename"] + ".asc"
  309. if not os.path.exists(filename):
  310. gscript.fatal(_("Unable to find AAIGrid raster file "
  311. "<%s> in archive.") % filename)
  312. elif format_ == "GML":
  313. for row in maplist:
  314. filename = row["filename"] + ".xml"
  315. if not os.path.exists(filename):
  316. gscript.fatal(_("Unable to find GML vector file "
  317. "<%s> in archive.") % filename)
  318. elif format_ == "pack":
  319. for row in maplist:
  320. if type_ == "stvds":
  321. filename = str(row["filename"].split(":")[0]) + ".pack"
  322. else:
  323. filename = row["filename"] + ".pack"
  324. if not os.path.exists(filename):
  325. gscript.fatal(_("Unable to find GRASS package file "
  326. "<%s> in archive.") % filename)
  327. else:
  328. gscript.fatal(_("Unsupported input format"))
  329. # Check the space time dataset
  330. id = output + "@" + mapset
  331. sp = dataset_factory(type_, id)
  332. if sp.is_in_db() and gscript.overwrite() == False:
  333. gscript.fatal(_("Space time %(t)s dataset <%(sp)s> is already in the "
  334. "database. Use the overwrite flag.") % {'t': type_,
  335. 'sp': sp.get_id()})
  336. # Import the maps
  337. if type_ == "strds":
  338. if format_ == "GTiff" or format_ == "AAIGrid":
  339. _import_raster_maps_from_gdal(maplist, overr, exp, location,
  340. link, format_, set_current_region)
  341. if format_ == "pack":
  342. _import_raster_maps(maplist, set_current_region)
  343. elif type_ == "stvds":
  344. if format_ == "GML":
  345. _import_vector_maps_from_gml(
  346. maplist, overr, exp, location, link)
  347. if format_ == "pack":
  348. _import_vector_maps(maplist)
  349. # Create the space time dataset
  350. if sp.is_in_db() and gscript.overwrite() == True:
  351. gscript.info(_("Overwrite space time %(sp)s dataset "
  352. "<%(id)s> and unregister all maps.") % {
  353. 'sp': sp.get_new_map_instance(None).get_type(),
  354. 'id': sp.get_id()})
  355. sp.delete()
  356. sp = sp.get_new_instance(id)
  357. temporal_type = init["temporal_type"]
  358. semantic_type = init["semantic_type"]
  359. relative_time_unit = None
  360. if temporal_type == "relative":
  361. if "relative_time_unit" not in init:
  362. gscript.fatal(_("Key word %s not found in init file.") % ("relative_time_unit"))
  363. relative_time_unit = init["relative_time_unit"]
  364. sp.set_relative_time_unit(relative_time_unit)
  365. gscript.verbose(_("Create space time %s dataset.") %
  366. sp.get_new_map_instance(None).get_type())
  367. sp.set_initial_values(temporal_type=temporal_type,
  368. semantic_type=semantic_type, title=title,
  369. description=descr)
  370. sp.insert()
  371. # register the maps
  372. fs = "|"
  373. register_maps_in_space_time_dataset(
  374. type=sp.get_new_map_instance(None).get_type(),
  375. name=output, file=new_list_file_name, start="file",
  376. end="file", unit=relative_time_unit, dbif=None, fs=fs,
  377. update_cmd_list=False)
  378. os.chdir(old_cwd)
  379. except:
  380. raise
  381. # Make sure the location is switched back correctly
  382. finally:
  383. if location:
  384. # Switch to the old location
  385. ret = gscript.run_command("g.mapset", mapset=old_env["MAPSET"],
  386. location=old_env["LOCATION_NAME"],
  387. gisdbase=old_env["GISDBASE"])
  388. gscript.set_raise_on_error(old_state)