stds_import.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. directory="/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, directory, 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 .core import get_current_mapset, get_tgis_message_interface
  28. from .register import register_maps_in_space_time_dataset
  29. from .factory import dataset_factory
  30. import grass.script as gscript
  31. from grass.exceptions import CalledModuleError
  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, memory=300):
  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. try:
  56. if link:
  57. gscript.run_command("r.external", input=filename,
  58. output=name,
  59. flags=impflags,
  60. overwrite=gscript.overwrite())
  61. else:
  62. gscript.run_command("r.in.gdal", input=filename,
  63. output=name, memory=memory,
  64. flags=impflags,
  65. overwrite=gscript.overwrite())
  66. except CalledModuleError:
  67. gscript.fatal(_("Unable to import/link raster map <%s> from file"
  68. " %s.") % (name, filename))
  69. # Set the color rules if present
  70. filename = row["filename"] + ".color"
  71. if os.path.isfile(filename):
  72. try:
  73. gscript.run_command("r.colors", map=name,
  74. rules=filename,
  75. overwrite=gscript.overwrite())
  76. except CalledModuleError:
  77. gscript.fatal(_("Unable to set the color rules for "
  78. "raster map <%s>.") % name)
  79. # Set the computational region from the last map imported
  80. if set_current_region is True:
  81. gscript.run_command("g.region", raster=name)
  82. ############################################################################
  83. def _import_raster_maps(maplist, set_current_region=False):
  84. # We need to disable the projection check because of its
  85. # simple implementation
  86. impflags = "o"
  87. for row in maplist:
  88. name = row["name"]
  89. filename = row["filename"] + ".pack"
  90. try:
  91. gscript.run_command("r.unpack", input=filename,
  92. output=name, flags=impflags,
  93. overwrite=gscript.overwrite(),
  94. verbose=True)
  95. except CalledModuleError:
  96. gscript.fatal(_("Unable to unpack raster map <%s> from file "
  97. "%s.") % (name, filename))
  98. # Set the computational region from the last map imported
  99. if set_current_region is True:
  100. gscript.run_command("g.region", raster=name)
  101. ############################################################################
  102. def _import_vector_maps_from_gml(maplist, overr, exp, location, link):
  103. impflags = "o"
  104. if exp or location:
  105. impflags += "e"
  106. for row in maplist:
  107. name = row["name"]
  108. filename = row["filename"] + ".xml"
  109. try:
  110. gscript.run_command("v.in.ogr", input=filename,
  111. output=name, flags=impflags,
  112. overwrite=gscript.overwrite())
  113. except CalledModuleError:
  114. gscript.fatal(_("Unable to import vector map <%s> from file "
  115. "%s.") % (name, filename))
  116. ############################################################################
  117. def _import_vector_maps(maplist):
  118. # We need to disable the projection check because of its
  119. # simple implementation
  120. impflags = "o"
  121. for row in maplist:
  122. # Separate the name from the layer
  123. name = row["name"].split(":")[0]
  124. # Import only unique maps
  125. if name in imported_maps:
  126. continue
  127. filename = row["filename"] + ".pack"
  128. try:
  129. gscript.run_command("v.unpack", input=filename,
  130. output=name, flags=impflags,
  131. overwrite=gscript.overwrite(),
  132. verbose=True)
  133. except CalledModuleError:
  134. gscript.fatal(_("Unable to unpack vector map <%s> from file "
  135. "%s.") % (name, filename))
  136. imported_maps[name] = name
  137. ############################################################################
  138. def import_stds(input, output, directory, title=None, descr=None, location=None,
  139. link=False, exp=False, overr=False, create=False,
  140. stds_type="strds", base=None, set_current_region=False,
  141. memory=300):
  142. """Import space time datasets of type raster and vector
  143. :param input: Name of the input archive file
  144. :param output: The name of the output space time dataset
  145. :param directory: The extraction directory
  146. :param title: The title of the new created space time dataset
  147. :param descr: The description of the new created
  148. space time dataset
  149. :param location: The name of the location that should be created,
  150. maps are imported into this location
  151. :param link: Switch to link raster maps instead importing them
  152. :param exp: Extend location extents based on new dataset
  153. :param overr: Override projection (use location's projection)
  154. :param create: Create the location specified by the "location"
  155. parameter and exit.
  156. Do not import the space time datasets.
  157. :param stds_type: The type of the space time dataset that
  158. should be imported
  159. :param base: The base name of the new imported maps, it will be
  160. extended using a numerical index.
  161. :param memory: Cache size for raster rows, used in r.in.gdal
  162. """
  163. old_state = gscript.raise_on_error
  164. gscript.set_raise_on_error(True)
  165. # Check if input file and extraction directory exits
  166. if not os.path.exists(input):
  167. gscript.fatal(_("Space time raster dataset archive <%s> not found")
  168. % input)
  169. if not create and not os.path.exists(directory):
  170. gscript.fatal(_("Extraction directory <%s> not found") % directory)
  171. tar = tarfile.open(name=input, mode='r')
  172. # Check for important files
  173. msgr = get_tgis_message_interface()
  174. msgr.message(_("Checking validity of input file (size: %0.1f MB). Make take a while..."
  175. % (os.path.getsize(input)/(1024*1024.0))))
  176. members = tar.getnames()
  177. # Make sure that the basenames of the files are used for comparison
  178. member_basenames = [os.path.basename(name) for name in members]
  179. if init_file_name not in member_basenames:
  180. gscript.fatal(_("Unable to find init file <%s>") % init_file_name)
  181. if list_file_name not in member_basenames:
  182. gscript.fatal(_("Unable to find list file <%s>") % list_file_name)
  183. if proj_file_name not in member_basenames:
  184. gscript.fatal(_("Unable to find projection file <%s>") % proj_file_name)
  185. msgr.message(_("Extracting data..."))
  186. tar.extractall(path=directory)
  187. tar.close()
  188. # We use a new list file name for map registration
  189. new_list_file_name = list_file_name + "_new"
  190. # Save current working directory path
  191. old_cwd = os.getcwd()
  192. # Switch into the data directory
  193. os.chdir(directory)
  194. # Check projection information
  195. if not location:
  196. temp_name = gscript.tempfile()
  197. temp_file = open(temp_name, "w")
  198. proj_name = os.path.abspath(proj_file_name)
  199. # We need to convert projection strings generated
  200. # from other programs than g.proj into
  201. # new line format so that the grass file comparison function
  202. # can be used to compare the projections
  203. proj_name_tmp = temp_name + "_in_projection"
  204. proj_file = open(proj_name, "r")
  205. proj_content = proj_file.read()
  206. proj_content = proj_content.replace(" +", "\n+")
  207. proj_content = proj_content.replace("\t+", "\n+")
  208. proj_file.close()
  209. proj_file = open(proj_name_tmp, "w")
  210. proj_file.write(proj_content)
  211. proj_file.close()
  212. p = gscript.start_command("g.proj", flags="j", stdout=temp_file)
  213. p.communicate()
  214. temp_file.close()
  215. if not gscript.compare_key_value_text_files(temp_name, proj_name_tmp,
  216. sep="="):
  217. if overr:
  218. gscript.warning(_("Projection information does not match. "
  219. "Proceeding..."))
  220. else:
  221. diff = ''.join(gscript.diff_files(temp_name, proj_name))
  222. gscript.warning(_("Difference between PROJ_INFO file of "
  223. "imported map and of current location:"
  224. "\n{diff}").format(diff=diff))
  225. gscript.fatal(_("Projection information does not match. "
  226. "Aborting."))
  227. # Create a new location based on the projection information and switch
  228. # into it
  229. old_env = gscript.gisenv()
  230. if location:
  231. try:
  232. proj4_string = open(proj_file_name, 'r').read()
  233. gscript.create_location(dbase=old_env["GISDBASE"],
  234. location=location,
  235. proj4=proj4_string)
  236. # Just create a new location and return
  237. if create:
  238. os.chdir(old_cwd)
  239. return
  240. except Exception as e:
  241. gscript.fatal(_("Unable to create location %(l)s. Reason: %(e)s")
  242. % {'l': location, 'e': str(e)})
  243. # Switch to the new created location
  244. try:
  245. gscript.run_command("g.mapset", mapset="PERMANENT",
  246. location=location,
  247. dbase=old_env["GISDBASE"])
  248. except CalledModuleError:
  249. gscript.fatal(_("Unable to switch to location %s") % location)
  250. # create default database connection
  251. try:
  252. gscript.run_command("t.connect", flags="d")
  253. except CalledModuleError:
  254. gscript.fatal(_("Unable to create default temporal database "
  255. "in new location %s") % location)
  256. try:
  257. # Make sure the temporal database exists
  258. from .core import init
  259. init()
  260. fs = "|"
  261. maplist = []
  262. mapset = get_current_mapset()
  263. list_file = open(list_file_name, "r")
  264. new_list_file = open(new_list_file_name, "w")
  265. # get number of lines to correctly form the suffix
  266. max_count = -1
  267. for max_count, l in enumerate(list_file):
  268. pass
  269. max_count += 1
  270. list_file.seek(0)
  271. # Read the map list from file
  272. line_count = 0
  273. while True:
  274. line = list_file.readline()
  275. if not line:
  276. break
  277. line_list = line.split(fs)
  278. # The filename is actually the base name of the map
  279. # that must be extended by the file suffix
  280. filename = line_list[0].strip().split(":")[0]
  281. if base:
  282. mapname = "%s_%s" % (base, gscript.get_num_suffix(line_count + 1,
  283. max_count))
  284. mapid = "%s@%s" % (mapname, mapset)
  285. else:
  286. mapname = filename
  287. mapid = mapname + "@" + mapset
  288. row = {}
  289. row["filename"] = filename
  290. row["name"] = mapname
  291. row["id"] = mapid
  292. row["start"] = line_list[1].strip()
  293. row["end"] = line_list[2].strip()
  294. new_list_file.write("%s%s%s%s%s\n" % (mapname, fs, row["start"],
  295. fs, row["end"]))
  296. maplist.append(row)
  297. line_count += 1
  298. list_file.close()
  299. new_list_file.close()
  300. # Read the init file
  301. fs = "="
  302. init = {}
  303. init_file = open(init_file_name, "r")
  304. while True:
  305. line = init_file.readline()
  306. if not line:
  307. break
  308. kv = line.split(fs)
  309. init[kv[0]] = kv[1].strip()
  310. init_file.close()
  311. if "temporal_type" not in init or \
  312. "semantic_type" not in init or \
  313. "number_of_maps" not in init:
  314. gscript.fatal(_("Key words %(t)s, %(s)s or %(n)s not found in init"
  315. " file.") % {'t': "temporal_type",
  316. 's': "semantic_type",
  317. 'n': "number_of_maps"})
  318. if line_count != int(init["number_of_maps"]):
  319. gscript.fatal(_("Number of maps mismatch in init and list file."))
  320. format_ = "GTiff"
  321. type_ = "strds"
  322. if "stds_type" in init:
  323. type_ = init["stds_type"]
  324. if "format" in init:
  325. format_ = init["format"]
  326. if stds_type != type_:
  327. gscript.fatal(_("The archive file is of wrong space time dataset"
  328. " type"))
  329. # Check the existence of the files
  330. if format_ == "GTiff":
  331. for row in maplist:
  332. filename = row["filename"] + ".tif"
  333. if not os.path.exists(filename):
  334. gscript.fatal(_("Unable to find GeoTIFF raster file "
  335. "<%s> in archive.") % filename)
  336. elif format_ == "AAIGrid":
  337. for row in maplist:
  338. filename = row["filename"] + ".asc"
  339. if not os.path.exists(filename):
  340. gscript.fatal(_("Unable to find AAIGrid raster file "
  341. "<%s> in archive.") % filename)
  342. elif format_ == "GML":
  343. for row in maplist:
  344. filename = row["filename"] + ".xml"
  345. if not os.path.exists(filename):
  346. gscript.fatal(_("Unable to find GML vector file "
  347. "<%s> in archive.") % filename)
  348. elif format_ == "pack":
  349. for row in maplist:
  350. if type_ == "stvds":
  351. filename = str(row["filename"].split(":")[0]) + ".pack"
  352. else:
  353. filename = row["filename"] + ".pack"
  354. if not os.path.exists(filename):
  355. gscript.fatal(_("Unable to find GRASS package file "
  356. "<%s> in archive.") % filename)
  357. else:
  358. gscript.fatal(_("Unsupported input format"))
  359. # Check the space time dataset
  360. id = output + "@" + mapset
  361. sp = dataset_factory(type_, id)
  362. if sp.is_in_db() and gscript.overwrite() is False:
  363. gscript.fatal(_("Space time %(t)s dataset <%(sp)s> is already in"
  364. " the database. Use the overwrite flag.") %
  365. {'t': type_, 'sp': sp.get_id()})
  366. # Import the maps
  367. if type_ == "strds":
  368. if format_ == "GTiff" or format_ == "AAIGrid":
  369. _import_raster_maps_from_gdal(maplist, overr, exp, location,
  370. link, format_, set_current_region,
  371. memory)
  372. if format_ == "pack":
  373. _import_raster_maps(maplist, set_current_region)
  374. elif type_ == "stvds":
  375. if format_ == "GML":
  376. _import_vector_maps_from_gml(
  377. maplist, overr, exp, location, link)
  378. if format_ == "pack":
  379. _import_vector_maps(maplist)
  380. # Create the space time dataset
  381. if sp.is_in_db() and gscript.overwrite() is True:
  382. gscript.info(_("Overwrite space time %(sp)s dataset "
  383. "<%(id)s> and unregister all maps.") %
  384. {'sp': sp.get_new_map_instance(None).get_type(),
  385. 'id': sp.get_id()})
  386. sp.delete()
  387. sp = sp.get_new_instance(id)
  388. temporal_type = init["temporal_type"]
  389. semantic_type = init["semantic_type"]
  390. relative_time_unit = None
  391. if temporal_type == "relative":
  392. if "relative_time_unit" not in init:
  393. gscript.fatal(_("Key word %s not found in init file.") %
  394. ("relative_time_unit"))
  395. relative_time_unit = init["relative_time_unit"]
  396. sp.set_relative_time_unit(relative_time_unit)
  397. gscript.verbose(_("Create space time %s dataset.") %
  398. sp.get_new_map_instance(None).get_type())
  399. sp.set_initial_values(temporal_type=temporal_type,
  400. semantic_type=semantic_type, title=title,
  401. description=descr)
  402. sp.insert()
  403. # register the maps
  404. fs = "|"
  405. register_maps_in_space_time_dataset(
  406. type=sp.get_new_map_instance(None).get_type(),
  407. name=output, file=new_list_file_name, start="file",
  408. end="file", unit=relative_time_unit, dbif=None, fs=fs,
  409. update_cmd_list=False)
  410. os.chdir(old_cwd)
  411. except:
  412. raise
  413. # Make sure the location is switched back correctly
  414. finally:
  415. if location:
  416. # Switch to the old location
  417. try:
  418. gscript.run_command("g.mapset", mapset=old_env["MAPSET"],
  419. location=old_env["LOCATION_NAME"],
  420. gisdbase=old_env["GISDBASE"])
  421. except CalledModuleError:
  422. gscript.warning(_("Switching to original location failed"))
  423. gscript.set_raise_on_error(old_state)