Parcourir la source

New temporal modules to set absolute and relative valid time for raster, vector and raster3d maps.

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@48376 15284696-431f-4ddb-bdfa-cd5b030d7da7
Soeren Gebbert il y a 13 ans
Parent
commit
8e3af3ed6b

+ 54 - 35
lib/python/tgis_abstract_datasets.py

@@ -26,7 +26,11 @@ from tgis_metadata import *
 
 
 class abstract_dataset(object):
 class abstract_dataset(object):
     """This is the base class for all datasets (raster, vector, raster3d, strds, stvds, str3ds)"""
     """This is the base class for all datasets (raster, vector, raster3d, strds, stvds, str3ds)"""
-    
+
+    def reset(self, ident):
+	"""Reset the internal structure and set the identifier"""
+	raise IOError("This method must be implemented in the subclasses")
+
     def get_type(self):
     def get_type(self):
         """Return the type of this class"""
         """Return the type of this class"""
         raise IOError("This method must be implemented in the subclasses")
         raise IOError("This method must be implemented in the subclasses")
@@ -305,15 +309,21 @@ class abstract_map_dataset(abstract_dataset):
             self.unregister(dbif)
             self.unregister(dbif)
 
 
             # Remove the strds register table
             # Remove the strds register table
-            sql = "DROP TABLE " + self.get_stds_register()
-            #print sql
-            dbif.cursor.execute(sql)
+            if self.get_stds_register():
+                sql = "DROP TABLE " + self.get_stds_register()
+                #print sql
+                try:
+                    dbif.cursor.execute(sql)
+                except:
+                    core.error("Unable to remove space time dataset register table " + self.get_stds_register())
 
 
             core.verbose("Delete " + self.get_type() + " dataset <" + self.get_id() + "> from temporal database")
             core.verbose("Delete " + self.get_type() + " dataset <" + self.get_id() + "> from temporal database")
 
 
             # Delete yourself from the database, trigger functions will take care of dependencies
             # Delete yourself from the database, trigger functions will take care of dependencies
             self.base.delete(dbif)
             self.base.delete(dbif)
 
 
+        self.reset(None)
+
         if connect == True:
         if connect == True:
             dbif.close()
             dbif.close()
 
 
@@ -360,18 +370,16 @@ class abstract_map_dataset(abstract_dataset):
             dbif.connect()
             dbif.connect()
             connect = True
             connect = True
 
 
-        # Select all data from the database
-        self.select(dbif)
-
         rows = None
         rows = None
 
 
-        # Remove the map from all registered space time datasets
-        if self.get_stds_register() != None:
-            # Select all stds tables in which this map is registered
-            sql = "SELECT id FROM " + self.get_stds_register()
-            #print sql
-            dbif.cursor.execute(sql)
-            rows = dbif.cursor.fetchall()
+        try:
+            if self.get_stds_register() != None:
+                # Select all stds tables in which this map is registered
+                sql = "SELECT id FROM " + self.get_stds_register()
+                dbif.cursor.execute(sql)
+                rows = dbif.cursor.fetchall()
+        except:
+            core.error("Unable to select space time dataset register table " + self.get_stds_register())
 
 
         if connect == True:
         if connect == True:
             dbif.close()
             dbif.close()
@@ -411,10 +419,6 @@ class abstract_space_time_dataset(abstract_dataset):
         """Set the name of the map register table"""
         """Set the name of the map register table"""
         raise IOError("This method must be implemented in the subclasses")
         raise IOError("This method must be implemented in the subclasses")
 
 
-    def reset(self, ident):
-	"""Reset the internal structure and set the identifier"""
-	raise IOError("This method must be implemented in the subclasses")
-
     def set_initial_values(self, granularity, temporal_type, semantic_type, \
     def set_initial_values(self, granularity, temporal_type, semantic_type, \
                            title=None, description=None):
                            title=None, description=None):
 
 
@@ -447,21 +451,26 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
         if self.get_map_register():
         if self.get_map_register():
             sql = "SELECT id FROM " + self.get_map_register()
             sql = "SELECT id FROM " + self.get_map_register()
-            dbif.cursor.execute(sql)
-            rows = dbif.cursor.fetchall()
-            # Unregister each registered map in the table
-            if rows:
-                for row in rows:
-                    # Unregister map
-                    map = self.get_new_map_instance(row["id"])
-                    self.unregister_map(map, dbif)
-
-            # Drop remove the map register table
-            sql = "DROP TABLE " + self.get_map_register()
-            dbif.cursor.execute(sql)
+            try:
+                dbif.cursor.execute(sql)
+                rows = dbif.cursor.fetchall()
+                # Unregister each registered map in the table
+                if rows:
+                    for row in rows:
+                        # Unregister map
+                        map = self.get_new_map_instance(row["id"])
+                        self.unregister_map(map, dbif)
+
+                # Drop remove the map register table
+                sql = "DROP TABLE " + self.get_map_register()
+                dbif.cursor.execute(sql)
+            except:
+                core.error("Unable to unregister maps from register table <" + self.get_map_register() + ">")
+                raise
 
 
         # Remove the primary key, the foreign keys will be removed by trigger
         # Remove the primary key, the foreign keys will be removed by trigger
         self.base.delete(dbif)
         self.base.delete(dbif)
+        self.reset(None)
 
 
         if connect == True:
         if connect == True:
             dbif.close()
             dbif.close()
@@ -533,7 +542,12 @@ class abstract_space_time_dataset(abstract_dataset):
             sql = sql.replace("TABLE_NAME", uuid_rand )
             sql = sql.replace("TABLE_NAME", uuid_rand )
             sql = sql.replace("MAP_ID", map_id)
             sql = sql.replace("MAP_ID", map_id)
             sql = sql.replace("STDS", self.get_type())
             sql = sql.replace("STDS", self.get_type())
-            dbif.cursor.executescript(sql)
+            try:
+                dbif.cursor.executescript(sql)
+            except:
+                core.error("Unable to create the space time " + map.get_type() +\
+                " dataset register table for " + map.get_type() + " map <" + map.get_id())
+                raise
 
 
             map_register_table = uuid_rand + "_" + self.get_type() + "_register"
             map_register_table = uuid_rand + "_" + self.get_type() + "_register"
             # Set the stds register table name and put it into the DB
             # Set the stds register table name and put it into the DB
@@ -553,11 +567,16 @@ class abstract_space_time_dataset(abstract_dataset):
             sql = sql.replace("STDS", self.get_type())
             sql = sql.replace("STDS", self.get_type())
 
 
             sql_script = ""
             sql_script = ""
-            sql_script += "BEGIN TRANSACTION;\n"
+            #sql_script += "BEGIN TRANSACTION;\n"
             sql_script += sql
             sql_script += sql
-            sql_script += "\n"
-            sql_script += "END TRANSACTION;"
-            dbif.cursor.executescript(sql_script)
+            #sql_script += "\n"
+            #sql_script += "END TRANSACTION;"
+            try:
+                dbif.cursor.executescript(sql_script)
+            except:
+                core.error("Unable to create the " + map.get_type() +\
+                " map register table for space time " + map.get_type() + " dataset <" + map.get_id())
+                raise
 
 
             # Trigger have been disabled due to peformance issues while registration
             # Trigger have been disabled due to peformance issues while registration
             ## We need raster specific trigger
             ## We need raster specific trigger

+ 101 - 5
lib/python/tgis_space_time_datasets.py

@@ -442,6 +442,11 @@ def register_maps_in_space_time_dataset(type, name, maps, start=None, increment=
                 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.")
                 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.")
             # Load the data from the grass file database
             # Load the data from the grass file database
             map.load()
             map.load()
+
+            if sp.get_temporal_type() == "absolute":
+                map.set_time_to_absolute()
+            else:
+                map.set_time_to_relative()
             #  Put it into the temporal database
             #  Put it into the temporal database
             map.insert(dbif)
             map.insert(dbif)
         else:
         else:
@@ -451,7 +456,7 @@ def register_maps_in_space_time_dataset(type, name, maps, start=None, increment=
 
 
         # Set the valid time
         # Set the valid time
         if start:
         if start:
-            assign_valid_time_to_map(sp.get_temporal_type(), map, start, increment, count, dbif)
+            assign_valid_time_to_map(ttype=sp.get_temporal_type(), map=map, start=start, end=None, increment=increment, mult=count, dbif=dbif)
 
 
         # Finally Register map in the space time dataset
         # Finally Register map in the space time dataset
         sp.register_map(map, dbif)
         sp.register_map(map, dbif)
@@ -534,8 +539,96 @@ def unregister_maps_from_space_time_datasets(type, name, maps, dbif = None):
 
 
     if connect == True:
     if connect == True:
         dbif.close()
         dbif.close()
-        
-def assign_valid_time_to_map(ttype, map, start, increment=None, mult=1, dbif = None):
+
+###############################################################################
+
+def assign_valid_time_to_maps(type, maps, ttype, start, end=None, increment=None, dbif = None):
+    """Use this method to assign valid time (absolute or relative) to raster,
+       raster3d and vector datasets.
+
+       It takes care of the correct update of the space time datasets from all
+       registered maps.
+
+       Valid end time and increment are mutual exclusive.
+
+       @type The type of the maps raster, raster3d or vector
+       @maps A comma separated list of map names
+       @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)
+       @start 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)
+       @increment Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
+    """
+
+    if end and increment:
+        core.fatal("Valid end time and increment are mutual exclusive")
+
+    # List of space time datasets to be updated
+    splist = {}
+
+    # We may need the mapset
+    mapset =  core.gisenv()["MAPSET"]
+
+    if dbif == None:
+        dbif = sql_database_interface()
+        dbif.connect()
+        connect = True
+
+    if maps.find(",") == -1:
+        maplist = (maps,)
+    else:
+        maplist = tuple(maps.split(","))
+
+    count = 0
+    for mapname in maplist:
+        mapname = mapname.strip()
+        # Check if the map name contains the mapset as well
+        if mapname.find("@") < 0:
+            mapid = mapname + "@" + mapset
+        else:
+            mapid = mapname
+            
+        if type == "raster":
+            map = raster_dataset(mapid)
+        if type == "raster3d":
+            map = raster3d_dataset(mapid)
+        if type == "vector":
+            map = vector_dataset(mapid)
+
+        if map.is_in_db(dbif) == False:
+            # Load the data from the grass file database
+            map.load()
+            if ttype == "absolute":
+                map.set_time_to_absolute()
+            else:
+                map.set_time_to_relative()
+            #  Put it into the temporal database
+            map.insert(dbif)
+        else:
+            map.select(dbif)
+            sprows = map.get_registered_datasets(dbif)
+            # Make an entry in the dataset list, using a dict make sure that
+            # each dataset is listed only once
+            if sprows != None:
+                for dataset in sprows:
+                    splist[dataset["id"]] = True
+            
+        # Set the valid time
+        assign_valid_time_to_map(ttype=ttype, map=map, start=start, end=end, increment=increment, mult=count, dbif=dbif)
+
+        count += 1
+
+    # Update all the space time datasets in which registered maps are changed there valid time
+    for name in splist.keys():
+        sp = map.get_new_stds_instance(name)
+        sp.select(dbif)
+        sp.update_from_registered_maps(dbif)
+
+    if connect == True:
+        dbif.close()
+
+
+###############################################################################
+
+def assign_valid_time_to_map(ttype, map, start, end, increment=None, mult=1, dbif = None):
     """Assign the valid time to a map dataset
     """Assign the valid time to a map dataset
 
 
        @ttype The temporal type which should be assigned and which the time format is of
        @ttype The temporal type which should be assigned and which the time format is of
@@ -544,7 +637,7 @@ def assign_valid_time_to_map(ttype, map, start, increment=None, mult=1, dbif = N
        @increment Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
        @increment Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
        @multi A multiplier for the increment
        @multi A multiplier for the increment
     """
     """
-
+    
     connect = False
     connect = False
 
 
     if dbif == None:
     if dbif == None:
@@ -560,7 +653,10 @@ def assign_valid_time_to_map(ttype, map, start, increment=None, mult=1, dbif = N
             time_format = "%Y-%m-%d"
             time_format = "%Y-%m-%d"
 
 
         start_time = datetime.strptime(start, time_format)
         start_time = datetime.strptime(start, time_format)
-        end_time = None
+        if end:
+            end_time = datetime.strptime(end, time_format)
+        else:
+            end_time = None
 
 
         # Add the increment
         # Add the increment
         if increment:
         if increment:

+ 1 - 1
lib/python/tgis_temporal_extent.py

@@ -419,7 +419,7 @@ class relative_temporal_extent(sql_database_interface):
         """Print information about this class in human readable style"""
         """Print information about this class in human readable style"""
         #      0123456789012345678901234567890
         #      0123456789012345678901234567890
         print " +-------------------- Relative time -----------------------------------------+"
         print " +-------------------- Relative time -----------------------------------------+"
-        print " |  Interval:................... " + str(self.get_interval())
+        print " | Interval:................... " + str(self.get_interval())
 
 
     def print_shell_info(self):
     def print_shell_info(self):
         """Print information about this class in shell style"""
         """Print information about this class in shell style"""

+ 5 - 0
lib/temporal/stds_map_register_table_template.sql

@@ -39,6 +39,11 @@ CREATE TABLE  SPACETIME_NAME_GRASS_MAP_register (
 --           (SELECT max(end_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN 
 --           (SELECT max(end_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN 
 --			(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
 --			(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
 --           ) WHERE id = "SPACETIME_ID";
 --           ) WHERE id = "SPACETIME_ID";
+
+--    UPDATE STDS_relative_time SET interval =
+--           (SELECT max(interval) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
+--       		(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
+--           ) WHERE id = "SPACETIME_ID";
 --    -- Update the spatial extent
 --    -- Update the spatial extent
 --    UPDATE STDS_spatial_extent SET north = 
 --    UPDATE STDS_spatial_extent SET north = 
 --           (SELECT max(north) FROM GRASS_MAP_spatial_extent WHERE GRASS_MAP_spatial_extent.id IN 
 --           (SELECT max(north) FROM GRASS_MAP_spatial_extent WHERE GRASS_MAP_spatial_extent.id IN 

+ 4 - 0
lib/temporal/update_stds_spatial_temporal_extent_template.sql

@@ -27,6 +27,10 @@ UPDATE STDS_absolute_time SET end_time =
        (SELECT max(end_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN 
        (SELECT max(end_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN 
     		(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
     		(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
        ) WHERE id = "SPACETIME_ID";
        ) WHERE id = "SPACETIME_ID";
+UPDATE STDS_relative_time SET interval =
+       (SELECT max(interval) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
+    		(SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
+       ) WHERE id = "SPACETIME_ID";
 -- Update the spatial extent
 -- Update the spatial extent
 UPDATE STDS_spatial_extent SET north = 
 UPDATE STDS_spatial_extent SET north = 
        (SELECT max(north) FROM GRASS_MAP_spatial_extent WHERE GRASS_MAP_spatial_extent.id IN 
        (SELECT max(north) FROM GRASS_MAP_spatial_extent WHERE GRASS_MAP_spatial_extent.id IN 

+ 2 - 0
temporal/Makefile

@@ -5,6 +5,8 @@ SUBDIRS = \
 	t.list \
 	t.list \
 	t.info \
 	t.info \
 	t.remove \
 	t.remove \
+	t.time.abs \
+	t.time.rel \
 	tr.register \
 	tr.register \
 	tr3.register \
 	tr3.register \
 	tv.register \
 	tv.register \

+ 1 - 0
temporal/t.create/t.create.py

@@ -120,6 +120,7 @@ def main():
     if sp.is_in_db(dbif) and grass.overwrite() == True:
     if sp.is_in_db(dbif) and grass.overwrite() == True:
         grass.info("Overwrite space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> and unregister all maps.")
         grass.info("Overwrite space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> and unregister all maps.")
         sp.delete(dbif)
         sp.delete(dbif)
+        sp = sp.get_new_instance(id)
 
 
     grass.info("Create space time " + sp.get_new_map_instance(None).get_type() + " dataset.")
     grass.info("Create space time " + sp.get_new_map_instance(None).get_type() + " dataset.")
 
 

+ 7 - 0
temporal/t.time.abs/Makefile

@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../
+
+PGM = t.time.abs
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script $(TEST_DST)

+ 0 - 0
temporal/t.time.abs/t.time.abs.html


+ 79 - 0
temporal/t.time.abs/t.time.abs.py

@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:	t.time.abs
+# AUTHOR(S):	Soeren Gebbert
+#
+# PURPOSE:	Set the absolute valid time interval for raster maps
+# COPYRIGHT:	(C) 2011 by the GRASS Development Team
+#
+#		This program is free software under the GNU General Public
+#		License (version 2). Read the file COPYING that comes with GRASS
+#		for details.
+#
+#############################################################################
+
+#%module
+#% description: Set the absolute valid time interval for maps of type raster, vector and raster3d
+#% keywords: time
+#% keywords: absolute
+#% keywords: raster
+#% keywords: vector
+#% keywords: raster3d
+#%end
+
+#%option
+#% key: maps
+#% type: string
+#% description: Name(s) of existing raster map(s)
+#% required: yes
+#% multiple: yes
+#%end
+
+#%option
+#% key: start
+#% type: string
+#% description: The valid start date and time of the first raster map. Time format is "yyyy-mm-dd HH:MM:SS" or only "yyyy-mm-dd"
+#% required: no
+#% multiple: no
+#%end
+
+#%option
+#% key: end
+#% type: string
+#% description: The valid end date and time of the first raster map. Time format is "yyyy-mm-dd HH:MM:SS" or only "yyyy-mm-dd". End time and increment are mutual exclusive.
+#% required: no
+#% multiple: no
+#%end
+
+#%option
+#% key: increment
+#% type: string
+#% description: Time increment between maps for valid time interval creation. Interval format: NNN seconds, minutes, hours, days, weeks, months, years
+#% required: no
+#% multiple: no
+#%end
+
+import grass.script as grass
+
+############################################################################
+
+def main():
+
+    # Get the options
+    maps = options["maps"]
+    start = options["start"]
+    end = options["end"]
+    increment = options["increment"]
+
+    # Make sure the temporal database exists
+    grass.create_temporal_database()
+    # Set valid absolute time to maps
+    grass.assign_valid_time_to_maps(type="raster", maps=maps, ttype="absolute", \
+                                    start=start, end=end, increment=increment, dbif=None)
+    
+if __name__ == "__main__":
+    options, flags = grass.core.parser()
+    main()
+

+ 39 - 0
temporal/t.time.abs/test.t.time.abs.sh

@@ -0,0 +1,39 @@
+# We test the absolute valid time interval creation with t.time.abs
+
+# We need to set a specific region in the
+# @preprocess step of this test. We generate
+# raster with r.mapcalc
+# The region setting should work for UTM and LL test locations
+g.region s=0 n=80 w=0 e=120 b=0 t=50 res=10 res3=10 -p3
+
+r.mapcalc --o expr="prec_1 = rand(0, 550)"
+r.mapcalc --o expr="prec_2 = rand(0, 450)"
+r.mapcalc --o expr="prec_3 = rand(0, 320)"
+r.mapcalc --o expr="prec_4 = rand(0, 510)"
+r.mapcalc --o expr="prec_5 = rand(0, 300)"
+r.mapcalc --o expr="prec_6 = rand(0, 650)"
+
+t.create --v --o type=strds temporaltype=absolute dataset=precip_abs1 gran="1 months" title="A test" descr="A test"
+t.create --v --o type=strds temporaltype=absolute dataset=precip_abs2 gran="1 months" title="A test" descr="A test"
+t.create --v --o type=strds temporaltype=absolute dataset=precip_abs3 gran="1 months" title="A test" descr="A test"
+
+t.time.abs --v maps=prec_1,prec_2,prec_3 start="2001-01-01" increment="1 months"
+t.info type=raster dataset=prec_1
+t.info type=raster dataset=prec_2
+t.info type=raster dataset=prec_3
+
+tr.register --v dataset=precip_abs1 maps=prec_1,prec_2,prec_3
+tr.register --v dataset=precip_abs2 maps=prec_1,prec_2,prec_3
+tr.register --v dataset=precip_abs3 maps=prec_1,prec_2,prec_3
+# Check if the space time datasets are updated correctly
+t.time.abs --v maps=prec_1,prec_2,prec_3 start="2011-01-01" increment="1 months"
+t.info type=strds dataset=precip_abs1
+
+t.time.abs --v maps=prec_4,prec_5 start="2001-01-01" end="2002-01-01"
+t.info type=raster dataset=prec_4
+t.info type=raster dataset=prec_5
+t.time.abs --v maps=prec_6 start="2001-01-01 00:00:00" end="2001-01-01 12:00:00"
+t.info type=raster dataset=prec_6
+
+t.remove --v type=raster dataset=prec_1,prec_2,prec_3,prec_4,prec_5,prec_6
+t.remove --v type=strds dataset=precip_abs1,precip_abs2,precip_abs3

+ 7 - 0
temporal/t.time.rel/Makefile

@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../
+
+PGM = t.time.rel
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script $(TEST_DST)

+ 0 - 0
temporal/t.time.rel/t.time.rel.html


+ 70 - 0
temporal/t.time.rel/t.time.rel.py

@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:	t.time.rel
+# AUTHOR(S):	Soeren Gebbert
+#
+# PURPOSE:	Set the relative valid time interval for raster maps
+# COPYRIGHT:	(C) 2011 by the GRASS Development Team
+#
+#		This program is free software under the GNU General Public
+#		License (version 2). Read the file COPYING that comes with GRASS
+#		for details.
+#
+#############################################################################
+
+#%module
+#% description: Set the relative valid time interval for maps of type raster, vector and raster3d
+#% keywords: time
+#% keywords: relative
+#% keywords: raster
+#% keywords: vector
+#% keywords: raster3d
+#%end
+
+#%option
+#% key: maps
+#% type: string
+#% description: Name(s) of existing raster map(s)
+#% required: yes
+#% multiple: yes
+#%end
+
+#%option
+#% key: start
+#% type: double
+#% description: The valid time value in [days]
+#% required: no
+#% multiple: no
+#%end
+
+#%option
+#% key: increment
+#% type: double
+#% description: Time increment between maps for valid time interval creation [days]
+#% required: no
+#% multiple: no
+#%end
+
+import grass.script as grass
+
+############################################################################
+
+def main():
+
+    # Get the options
+    maps = options["maps"]
+    start = options["start"]
+    increment = options["increment"]
+
+    # Make sure the temporal database exists
+    grass.create_temporal_database()
+    # Set valid relative time to maps
+    grass.assign_valid_time_to_maps(type="raster", maps=maps, ttype="relative", \
+                                    start=start, end=None, increment=increment, dbif=None)
+
+if __name__ == "__main__":
+    options, flags = grass.core.parser()
+    main()
+

+ 39 - 0
temporal/t.time.rel/test.t.time.rel.sh

@@ -0,0 +1,39 @@
+# We test the relative valid time interval creation with t.time.rel
+
+# We need to set a specific region in the
+# @preprocess step of this test. We generate
+# raster with r.mapcalc
+# The region setting should work for UTM and LL test locations
+g.region s=0 n=80 w=0 e=120 b=0 t=50 res=10 res3=10 -p3
+
+r.mapcalc --o expr="prec_1 = rand(0, 550)"
+r.mapcalc --o expr="prec_2 = rand(0, 450)"
+r.mapcalc --o expr="prec_3 = rand(0, 320)"
+r.mapcalc --o expr="prec_4 = rand(0, 510)"
+r.mapcalc --o expr="prec_5 = rand(0, 300)"
+r.mapcalc --o expr="prec_6 = rand(0, 650)"
+
+t.create --v --o type=strds temporaltype=relative dataset=precip_rel1 gran=2 title="A test" descr="A test"
+t.create --v --o type=strds temporaltype=relative dataset=precip_rel2 gran=2 title="A test" descr="A test"
+t.create --v --o type=strds temporaltype=relative dataset=precip_rel3 gran=2 title="A test" descr="A test"
+
+t.time.rel --v maps=prec_1,prec_2,prec_3 start=5 increment=2
+t.info type=raster dataset=prec_1
+t.info type=raster dataset=prec_2
+t.info type=raster dataset=prec_3
+
+tr.register --v dataset=precip_rel1 maps=prec_1,prec_2,prec_3
+tr.register --v dataset=precip_rel2 maps=prec_1,prec_2,prec_3
+tr.register --v dataset=precip_rel3 maps=prec_1,prec_2,prec_3
+# Check if the space time datasets are updated correctly
+t.time.rel --v maps=prec_1,prec_2,prec_3 start=0 increment=1000
+t.info type=strds dataset=precip_rel1
+
+t.time.rel --v maps=prec_4,prec_5 start=5000
+t.info type=raster dataset=prec_4
+t.info type=raster dataset=prec_5
+t.time.rel --v maps=prec_6 start=6000
+t.info type=raster dataset=prec_6
+
+t.remove --v type=raster dataset=prec_1,prec_2,prec_3,prec_4,prec_5,prec_6
+t.remove --v type=strds dataset=precip_rel1,precip_rel2,precip_rel3