[GRASS-SVN] r48748 - grass/trunk/lib/python/temporal
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Oct 12 05:38:16 EDT 2011
Author: huhabla
Date: 2011-10-12 02:38:16 -0700 (Wed, 12 Oct 2011)
New Revision: 48748
Added:
grass/trunk/lib/python/temporal/abstract_dataset.py
grass/trunk/lib/python/temporal/abstract_map_dataset.py
grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
grass/trunk/lib/python/temporal/space_time_datasets_tools.py
Modified:
grass/trunk/lib/python/temporal/Makefile
grass/trunk/lib/python/temporal/__init__.py
grass/trunk/lib/python/temporal/space_time_datasets.py
Log:
Better code managament
Modified: grass/trunk/lib/python/temporal/Makefile
===================================================================
--- grass/trunk/lib/python/temporal/Makefile 2011-10-12 07:04:50 UTC (rev 48747)
+++ grass/trunk/lib/python/temporal/Makefile 2011-10-12 09:38:16 UTC (rev 48748)
@@ -8,7 +8,7 @@
GDIR = $(PYDIR)/grass
DSTDIR = $(GDIR)/temporal
-MODULES = base core abstract_datasets space_time_datasets metadata spatial_extent temporal_extent datetime_math
+MODULES = base core abstract_dataset abstract_map_dataset abstract_space_time_dataset space_time_datasets space_time_datasets_tools metadata spatial_extent temporal_extent datetime_math
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
Modified: grass/trunk/lib/python/temporal/__init__.py
===================================================================
--- grass/trunk/lib/python/temporal/__init__.py 2011-10-12 07:04:50 UTC (rev 48747)
+++ grass/trunk/lib/python/temporal/__init__.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -3,5 +3,9 @@
from temporal_extent import *
from spatial_extent import *
from metadata import *
+from abstract_dataset import *
+from abstract_map_dataset import *
+from abstract_space_time_dataset import *
from space_time_datasets import *
+from space_time_datasets_tools import *
from datetime_math import *
Added: grass/trunk/lib/python/temporal/abstract_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_dataset.py (rev 0)
+++ grass/trunk/lib/python/temporal/abstract_dataset.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -0,0 +1,229 @@
+"""!@package grass.temporal
+
+ at brief GRASS Python scripting module (temporal GIS functions)
+
+Temporal GIS related functions to be used in temporal GIS Python library package.
+
+Usage:
+
+ at code
+import grass.temporal as tgis
+
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+import uuid
+import copy
+from temporal_extent import *
+from spatial_extent import *
+from metadata import *
+
+class abstract_dataset(object):
+ """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
+
+ @param ident: The identifier of the dataset
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_type(self):
+ """Return the type of this class"""
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_new_instance(self, ident):
+ """Return a new instance with the type of this class
+
+ @param ident: The identifier of the dataset
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_id(self):
+ return self.base.get_id()
+
+ def get_absolute_time(self):
+ """Returns a tuple of the start, the end valid time and the timezone of the map
+ @return A tuple of (start_time, end_time, timezone)
+ """
+
+ start = self.absolute_time.get_start_time()
+ end = self.absolute_time.get_end_time()
+ tz = self.absolute_time.get_timezone()
+
+ return (start, end, tz)
+
+ def get_relative_time(self):
+ """Returns the relative time interval (start_time, end_time) or None if not present"""
+
+ start = self.relative_time.get_start_time()
+ end = self.relative_time.get_end_time()
+
+ return (start, end)
+
+ def get_temporal_type(self):
+ """Return the temporal type of this dataset"""
+ return self.base.get_ttype()
+
+ def get_spatial_extent(self):
+ """Return a tuple of spatial extent (north, south, east, west, top, bottom) """
+
+ north = self.spatial_extent.get_north()
+ south = self.spatial_extent.get_south()
+ east = self.spatial_extent.get_east()
+ west = self.spatial_extent.get_west()
+ top = self.spatial_extent.get_top()
+ bottom = self.spatial_extent.get_bottom()
+
+ return (north, south, east, west, top, bottom)
+
+ def select(self, dbif=None):
+ """Select temporal dataset entry from database and fill up the internal structure"""
+ self.base.select(dbif)
+ if self.is_time_absolute():
+ self.absolute_time.select(dbif)
+ if self.is_time_relative():
+ self.relative_time.select(dbif)
+ self.spatial_extent.select(dbif)
+ self.metadata.select(dbif)
+
+ def is_in_db(self, dbif=None):
+ """Check if the temporal dataset entry is in the database"""
+ return self.base.is_in_db(dbif)
+
+ def delete(self):
+ """Delete temporal dataset entry from database if it exists"""
+ raise IOError("This method must be implemented in the subclasses")
+
+ def insert(self, dbif=None):
+ """Insert temporal dataset entry into database from the internal structure"""
+ self.base.insert(dbif)
+ if self.is_time_absolute():
+ self.absolute_time.insert(dbif)
+ if self.is_time_relative():
+ self.relative_time.insert(dbif)
+ self.spatial_extent.insert(dbif)
+ self.metadata.insert(dbif)
+
+ def update(self, dbif=None):
+ """Update temporal dataset entry of database from the internal structure
+ excluding None variables
+ """
+ self.base.update(dbif)
+ if self.is_time_absolute():
+ self.absolute_time.update(dbif)
+ if self.is_time_relative():
+ self.relative_time.update(dbif)
+ self.spatial_extent.update(dbif)
+ self.metadata.update(dbif)
+
+ def update_all(self, dbif=None):
+ """Update temporal dataset entry of database from the internal structure
+ and include None varuables.
+
+ @param dbif: The database interface to be used
+ """
+ self.base.update_all(dbif)
+ if self.is_time_absolute():
+ self.absolute_time.update_all(dbif)
+ if self.is_time_relative():
+ self.relative_time.update_all(dbif)
+ self.spatial_extent.update_all(dbif)
+ self.metadata.update_all(dbif)
+
+ def print_self(self):
+ """Print the content of the internal structure to stdout"""
+ self.base.print_self()
+ if self.is_time_absolute():
+ self.absolute_time.print_self()
+ if self.is_time_relative():
+ self.relative_time.print_self()
+ self.spatial_extent.print_self()
+ self.metadata.print_self()
+
+ def print_info(self):
+ """Print information about this class in human readable style"""
+
+ if self.get_type() == "raster":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Raster Dataset ----------------------------------------+"
+ if self.get_type() == "raster3d":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Raster3d Dataset --------------------------------------+"
+ if self.get_type() == "vector":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Vector Dataset ----------------------------------------+"
+ if self.get_type() == "strds":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Space Time Raster Dataset -----------------------------+"
+ if self.get_type() == "str3ds":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Space Time Raster3d Dataset ---------------------------+"
+ if self.get_type() == "stvds":
+ # 1 2 3 4 5 6 7
+ # 0123456789012345678901234567890123456789012345678901234567890123456789012345678
+ print ""
+ print " +-------------------- Space Time Vector Dataset -----------------------------+"
+ print " | |"
+ self.base.print_info()
+ if self.is_time_absolute():
+ self.absolute_time.print_info()
+ if self.is_time_relative():
+ self.relative_time.print_info()
+ self.spatial_extent.print_info()
+ self.metadata.print_info()
+ print " +----------------------------------------------------------------------------+"
+
+ def print_shell_info(self):
+ """Print information about this class in shell style"""
+ self.base.print_shell_info()
+ if self.is_time_absolute():
+ self.absolute_time.print_shell_info()
+ if self.is_time_relative():
+ self.relative_time.print_shell_info()
+ self.spatial_extent.print_shell_info()
+ self.metadata.print_shell_info()
+
+ def set_time_to_absolute(self):
+ self.base.set_ttype("absolute")
+
+ def set_time_to_relative(self):
+ self.base.set_ttype("relative")
+
+ def is_time_absolute(self):
+ if self.base.D.has_key("temporal_type"):
+ return self.base.get_ttype() == "absolute"
+ else:
+ return None
+
+ def is_time_relative(self):
+ if self.base.D.has_key("temporal_type"):
+ return self.base.get_ttype() == "relative"
+ else:
+ return None
+
+ def temporal_relation(self, map):
+ """Return the temporal relation of this and the provided temporal map"""
+ if self.is_time_absolute() and map.is_time_absolute():
+ return self.absolute_time.temporal_relation(map.absolute_time)
+ if self.is_time_relative() and map.is_time_relative():
+ return self.relative_time.temporal_relation(map.relative_time)
+ return None
+
Added: grass/trunk/lib/python/temporal/abstract_map_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_map_dataset.py (rev 0)
+++ grass/trunk/lib/python/temporal/abstract_map_dataset.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -0,0 +1,264 @@
+"""!@package grass.temporal
+
+ at brief GRASS Python scripting module (temporal GIS functions)
+
+Temporal GIS related functions to be used in temporal GIS Python library package.
+
+Usage:
+
+ at code
+import grass.temporal as tgis
+
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+from abstract_dataset import *
+
+###############################################################################
+
+class abstract_map_dataset(abstract_dataset):
+ """This is the base class for all maps (raster, vector, raster3d)
+ providing additional function to set the valid time and the spatial extent.
+ """
+
+ def get_new_stds_instance(self, ident):
+ """Return a new space time dataset instance in which maps are stored with the type of this class
+
+ @param ident: The identifier of the dataset
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_stds_register(self):
+ """Return the space time dataset register table name in which stds are listed in which this map is registered"""
+ raise IOError("This method must be implemented in the subclasses")
+
+ def set_stds_register(self, name):
+ """Set the space time dataset register table name.
+
+ This table stores all space time datasets in which this map is registered.
+
+ @param ident: The name of the register table
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def set_absolute_time(self, start_time, end_time=None, timezone=None):
+ """Set the absolute time interval with start time and end time
+
+ @param start_time: a datetime object specifying the start time of the map
+ @param end_time: a datetime object specifying the end time of the map
+ @param timezone: Thee timezone of the map
+
+ """
+ if start_time != None and not isinstance(start_time, datetime) :
+ core.fatal(_("Start time must be of type datetime"))
+
+ if end_time != None and not isinstance(end_time, datetime) :
+ core.fatal(_("End time must be of type datetime"))
+
+ if start_time != None and end_time != None:
+ if start_time >= end_time:
+ core.error(_("End time must be later than start time"))
+ return False
+
+ self.base.set_ttype("absolute")
+
+ self.absolute_time.set_start_time(start_time)
+ self.absolute_time.set_end_time(end_time)
+ self.absolute_time.set_timezone(timezone)
+
+ return True
+
+ def update_absolute_time(self, start_time, end_time=None, timezone=None, dbif = None):
+ """Update the absolute time
+
+ @param start_time: a datetime object specifying the start time of the map
+ @param end_time: a datetime object specifying the end time of the map
+ @param timezone: Thee timezone of the map
+ """
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ self.set_absolute_time(start_time, end_time, timezone)
+ self.absolute_time.update_all(dbif)
+ self.base.update(dbif)
+
+ if connect == True:
+ dbif.close()
+
+ def set_relative_time(self, start_time, end_time=None):
+ """Set the relative time interval
+
+ @param start_time: A double value in days
+ @param end_time: A double value in days
+
+ """
+ if start_time != None and end_time != None:
+ if abs(float(start_time)) >= abs(float(end_time)):
+ core.error(_("End time must be greater than start time"))
+ return False
+
+ self.base.set_ttype("relative")
+
+ self.relative_time.set_start_time(float(start_time))
+ if end_time != None:
+ self.relative_time.set_end_time(float(end_time))
+ else:
+ self.relative_time.set_end_time(None)
+
+ return True
+
+ def update_relative_time(self, start_time, end_time=None, dbif = None):
+ """Update the relative time interval
+
+ @param start_time: A double value in days
+ @param end_time: A double value in days
+ @param dbif: The database interface to be used
+ """
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ self.set_relative_time(start_time, end_time)
+ self.relative_time.update_all(dbif)
+ self.base.update(dbif)
+ dbif.connection.commit()
+
+ if connect == True:
+ dbif.close()
+
+ def set_spatial_extent(self, north, south, east, west, top=0, bottom=0):
+ """Set the spatial extent of the map
+
+ @param north: The northern edge
+ @param south: The southern edge
+ @param east: The eastern edge
+ @param west: The western edge
+ @param top: The top edge
+ @param bottom: The bottom ege
+ """
+ self.spatial_extent.set_spatial_extent(north, south, east, west, top, bottom)
+
+ def delete(self, dbif=None):
+ """Delete a map entry from database if it exists
+
+ Remove dependent entries:
+ * Remove the map entry in each space time dataset in which this map is registered
+ * Remove the space time dataset register table
+
+ @param dbif: The database interface to be used
+ """
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ if self.is_in_db(dbif):
+
+ # SELECT all needed informations from the database
+ self.select(dbif)
+
+ # First we unregister from all dependent space time datasets
+ self.unregister(dbif)
+
+ # Remove the strds register table
+ 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 <%s>") % (self.get_stds_register()))
+
+ core.verbose(_("Delete %s dataset <%s> from temporal database") % (self.get_type(), self.get_id()))
+
+ # Delete yourself from the database, trigger functions will take care of dependencies
+ self.base.delete(dbif)
+
+ self.reset(None)
+ dbif.connection.commit()
+
+ if connect == True:
+ dbif.close()
+
+ def unregister(self, dbif=None):
+ """ Remove the map entry in each space time dataset in which this map is registered
+
+ @param dbif: The database interface to be used
+ """
+
+ core.verbose(_("Unregister %s dataset <%s> from space time datasets") % (self.get_type(), self.get_id()))
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ # Get all datasets in which this map is registered
+ rows = self.get_registered_datasets(dbif)
+
+ # For each stds in which the map is registered
+ if rows:
+ for row in rows:
+ # Create a space time dataset object to remove the map
+ # from its register
+ stds = self.get_new_stds_instance(row["id"])
+ stds.select(dbif)
+ stds.unregister_map(self, dbif)
+ # Take care to update the space time dataset after
+ # the map has been unregistred
+ stds.update_from_registered_maps(dbif)
+
+ dbif.connection.commit()
+
+ if connect == True:
+ dbif.close()
+
+ def get_registered_datasets(self, dbif=None):
+ """Return all space time dataset ids in which this map is registered as
+ dictionary like rows with column "id" or None if this map is not registered in any
+ space time dataset.
+
+ @param dbif: The database interface to be used
+ """
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ rows = None
+
+ 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 <%s>") % (self.get_stds_register()))
+
+ if connect == True:
+ dbif.close()
+
+ return rows
+
Added: grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_space_time_dataset.py (rev 0)
+++ grass/trunk/lib/python/temporal/abstract_space_time_dataset.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -0,0 +1,675 @@
+"""!@package grass.temporal
+
+ at brief GRASS Python scripting module (temporal GIS functions)
+
+Temporal GIS related functions to be used in temporal GIS Python library package.
+
+Usage:
+
+ at code
+import grass.temporal as tgis
+
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+from abstract_dataset import *
+
+###############################################################################
+
+class abstract_space_time_dataset(abstract_dataset):
+ """Abstract space time dataset class
+
+ This class represents a space time dataset. Convenient functions
+ to select, update, insert or delete objects of this type in the SQL
+ temporal database exists as well as functions to register or unregister
+ raster maps.
+
+ Parts of the temporal logic are implemented in the SQL temporal database,
+ like the computation of the temporal and spatial extent as well as the
+ collecting of metadata.
+ """
+ def __init__(self, ident):
+ self.reset(ident)
+
+ def get_new_instance(self, ident=None):
+ """Return a new instance with the type of this class
+
+ @param ident: The unique identifier of the new object
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_new_map_instance(self, ident=None):
+ """Return a new instance of a map dataset which is associated with the type of this class
+
+ @param ident: The unique identifier of the new object
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def get_map_register(self):
+ """Return the name of the map register table"""
+ raise IOError("This method must be implemented in the subclasses")
+
+ def set_map_register(self, name):
+ """Set the name of the map register table
+
+ This table stores all map names which are registered in this space time dataset.
+
+ @param name: The name of the register table
+ """
+ raise IOError("This method must be implemented in the subclasses")
+
+ def set_initial_values(self, granularity, temporal_type, semantic_type, \
+ title=None, description=None):
+ """Set the initial values of the space time dataset
+
+ @param granularity: The temporal granularity of this dataset. This value
+ should be computed by the space time dataset itself,
+ based on the granularity of the registered maps
+ @param temporal_type: The temporal type of this space time dataset (absolute or relative)
+ @param semantic_type: The semantic type of this dataset
+ @param title: The title
+ @param description: The description of this dataset
+ """
+
+ if temporal_type == "absolute":
+ self.set_time_to_absolute()
+ self.absolute_time.set_granularity(granularity)
+ elif temporal_type == "relative":
+ self.set_time_to_relative()
+ self.relative_time.set_granularity(granularity)
+ else:
+ core.fatal(_("Unknown temporal type \"%s\"") % (temporal_type))
+
+ self.base.set_semantic_type(semantic_type)
+ self.metadata.set_title(title)
+ self.metadata.set_description(description)
+
+ def get_initial_values(self):
+ """Return the initial values: granularity, temporal_type, semantic_type, title, description"""
+
+ temporal_type = self.get_temporal_type()
+
+ if temporal_type == "absolute":
+ granularity = self.absolute_time.get_granularity()
+ elif temporal_type == "relative":
+ granularity = self.relative_time.get_granularity()
+
+ semantic_type = self.base.get_semantic_type()
+ title = self.metadata.get_title()
+ description = self.metadata.get_description()
+
+ return granularity, temporal_type, semantic_type, title, description
+
+ def get_temporal_relation_matrix(self, dbif=None):
+ """Return the temporal relation matrix of all registered maps as listof lists
+
+ The temproal relation matrix includes the temporal relations between
+ all registered maps. The relations are strings stored in a list of lists.
+
+ @param dbif: The database interface to be used
+ """
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ matrix = []
+
+ maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+
+ # Create the temporal relation matrix
+ # Add the map names first
+ row = []
+ for map in maps:
+ row.append(map.get_id())
+ matrix.append(row)
+
+ for mapA in maps:
+ row = []
+ for mapB in maps:
+ row.append(mapA.temporal_relation(mapB))
+ matrix.append(row)
+
+ if connect == True:
+ dbif.close()
+
+ return matrix
+
+ def get_registered_maps_as_objects(self, where = None, order = None, dbif=None):
+ """Return all registered maps as ordered object list
+
+ @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
+ @param order: The SQL order statement to be used to order the objects in the list without "ORDER BY"
+ @param dbif: The database interface to be used
+
+ In case nothing found None is returned
+ """
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ obj_list = []
+
+ rows = self.get_registered_maps("id", where, order, dbif)
+
+ if rows:
+ for row in rows:
+ map = self.get_new_map_instance(row["id"])
+ map.select(dbif)
+ obj_list.append(copy.copy(map))
+
+ if connect == True:
+ dbif.close()
+
+ return obj_list
+
+ def get_registered_maps(self, columns=None, where = None, order = None, dbif=None):
+ """Return sqlite rows of all registered maps.
+
+ Each row includes all columns specified in the datatype specific view
+
+ @param columns: Columns to be selected as SQL compliant string
+ @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
+ @param order: The SQL order statement to be used to order the objects in the list without "ORDER BY"
+ @param dbif: The database interface to be used
+
+ In case nothing found None is returned
+ """
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ rows = None
+
+ if self.get_map_register():
+ # Use the correct temporal table
+ if self.get_temporal_type() == "absolute":
+ map_view = self.get_new_map_instance(None).get_type() + "_view_abs_time"
+ else:
+ map_view = self.get_new_map_instance(None).get_type() + "_view_rel_time"
+
+ if columns:
+ sql = "SELECT %s FROM %s WHERE %s.id IN (SELECT id FROM %s)" % (columns, map_view, map_view, self.get_map_register())
+ else:
+ sql = "SELECT * FROM %s WHERE %s.id IN (SELECT id FROM %s)" % (map_view, map_view, self.get_map_register())
+
+ if where:
+ sql += " AND %s" % (where)
+ if order:
+ sql += " ORDER BY %s" % (order)
+
+ try:
+ dbif.cursor.execute(sql)
+ rows = dbif.cursor.fetchall()
+ except:
+ if connect == True:
+ dbif.close()
+ core.error(_("Unable to get map ids from register table <%s>") % (self.get_map_register()))
+ raise
+
+ if connect == True:
+ dbif.close()
+
+ return rows
+
+ def delete(self, dbif=None):
+ """Delete a space time dataset from the temporal database
+
+ This method removes the space time dataset from the temporal database and drops its map register table
+
+ @param dbif: The database interface to be used
+ """
+ # First we need to check if maps are registered in this dataset and
+ # unregister them
+
+ core.verbose(_("Delete space time %s dataset <%s> from temporal database") % (self.get_new_map_instance(ident=None).get_type(), self.get_id()))
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ # SELECT all needed informations from the database
+ self.select(dbif)
+
+ core.verbose(_("Drop map register table: %s") % (self.get_map_register()))
+ if self.get_map_register():
+ rows = self.get_registered_maps("id", None, None, dbif)
+ # 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)
+ try:
+ # Drop the map register table
+ sql = "DROP TABLE " + self.get_map_register()
+ dbif.cursor.execute(sql)
+ dbif.connection.commit()
+ except:
+ if connect == True:
+ dbif.close()
+ core.error(_("Unable to drop table <%s>") % (self.get_map_register()))
+ raise
+
+ # Remove the primary key, the foreign keys will be removed by trigger
+ self.base.delete(dbif)
+ self.reset(None)
+
+ if connect == True:
+ dbif.close()
+
+ def register_map(self, map, dbif=None):
+ """ Register a map in the space time dataset.
+
+ This method takes care of the registration of a map
+ in a space time dataset.
+
+ In case the map is already registered this function will break with a warning
+ and return False
+
+ @param dbif: The database interface to be used
+ """
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ if map.is_in_db(dbif) == False:
+ dbif.close()
+ core.fatal(_("Only maps with absolute or relative valid time can be registered"))
+
+ core.verbose(_("Register %s map <%s> in space time %s dataset <%s>") % (map.get_type(), map.get_id(), map.get_type(), self.get_id()))
+
+ # First select all data from the database
+ map.select(dbif)
+ map_id = map.base.get_id()
+ map_name = map.base.get_name()
+ map_mapset = map.base.get_mapset()
+ map_register_table = map.get_stds_register()
+
+ #print "Map register table", map_register_table
+
+ # Get basic info
+ stds_name = self.base.get_name()
+ stds_mapset = self.base.get_mapset()
+ stds_register_table = self.get_map_register()
+
+ #print "STDS register table", stds_register_table
+
+ if stds_mapset != map_mapset:
+ dbif.close()
+ core.fatal(_("Only maps from the same mapset can be registered"))
+
+ # Check if map is already registred
+ if stds_register_table:
+ if dbmi.paramstyle == "qmark":
+ sql = "SELECT id FROM " + stds_register_table + " WHERE id = (?)"
+ else:
+ sql = "SELECT id FROM " + stds_register_table + " WHERE id = (%s)"
+ dbif.cursor.execute(sql, (map_id,))
+ row = dbif.cursor.fetchone()
+ # In case of no entry make a new one
+ if row and row[0] == map_id:
+ if connect == True:
+ dbif.close()
+ core.warning(_("Map <%s> is already registered.") % (map_id))
+ return False
+
+ # Create tables
+ sql_path = get_sql_template_path()
+
+ # We need to create the stmap raster register table bevor we can register the map
+ if map_register_table == None:
+ # Create a unique id
+ uuid_rand = "map_" + str(uuid.uuid4()).replace("-", "")
+
+ map_register_table = uuid_rand + "_" + self.get_type() + "_register"
+
+ # Read the SQL template
+ sql = open(os.path.join(sql_path, "map_stds_register_table_template.sql"), 'r').read()
+ # Create the raster, raster3d and vector tables
+ sql = sql.replace("GRASS_MAP", map.get_type())
+ sql = sql.replace("MAP_NAME", map_name + "_" + map_mapset )
+ sql = sql.replace("TABLE_NAME", uuid_rand )
+ sql = sql.replace("MAP_ID", map_id)
+ sql = sql.replace("STDS", self.get_type())
+ try:
+ if dbmi.__name__ == "sqlite3":
+ dbif.cursor.executescript(sql)
+ else:
+ dbif.cursor.execute(sql)
+ except:
+ if connect == True:
+ dbif.close()
+ core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
+ (map.get_type(), map.get_id()))
+ raise
+
+ # Set the stds register table name and put it into the DB
+ map.set_stds_register(map_register_table)
+ map.metadata.update(dbif)
+
+ core.verbose(_("Created register table <%s> for %s map <%s>") % \
+ (map_register_table, map.get_type(), map.get_id()))
+
+ # We need to create the table and register it
+ if stds_register_table == None:
+ # Create table name
+ stds_register_table = stds_name + "_" + stds_mapset + "_" + map.get_type() + "_register"
+ # Read the SQL template
+ sql = open(os.path.join(sql_path, "stds_map_register_table_template.sql"), 'r').read()
+ # Create the raster, raster3d and vector tables
+ sql = sql.replace("GRASS_MAP", map.get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ sql = sql.replace("SPACETIME_ID", self.base.get_id())
+ sql = sql.replace("STDS", self.get_type())
+
+ sql_script = ""
+ sql_script += "BEGIN TRANSACTION;\n"
+ sql_script += sql
+ sql_script += "\n"
+ sql_script += "END TRANSACTION;"
+ try:
+ if dbmi.__name__ == "sqlite3":
+ dbif.cursor.executescript(sql_script)
+ else:
+ dbif.cursor.execute(sql_script)
+ dbif.connection.commit()
+ except:
+ if connect == True:
+ dbif.close()
+ core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
+ (map.get_type(), map.get_id()))
+ raise
+
+ # Set the map register table name and put it into the DB
+ self.set_map_register(stds_register_table)
+ self.metadata.update(dbif)
+
+ core.verbose(_("Created register table <%s> for space time %s dataset <%s>") % \
+ (stds_register_table, map.get_type(), self.get_id()))
+
+ # Register the stds in the map stds register table
+ # Check if the entry is already there
+ if dbmi.paramstyle == "qmark":
+ sql = "SELECT id FROM " + map_register_table + " WHERE id = ?"
+ else:
+ sql = "SELECT id FROM " + map_register_table + " WHERE id = %s"
+ dbif.cursor.execute(sql, (self.base.get_id(),))
+ row = dbif.cursor.fetchone()
+
+ # In case of no entry make a new one
+ if row == None:
+ if dbmi.paramstyle == "qmark":
+ sql = "INSERT INTO " + map_register_table + " (id) " + "VALUES (?)"
+ else:
+ sql = "INSERT INTO " + map_register_table + " (id) " + "VALUES (%s)"
+ #print sql
+ dbif.cursor.execute(sql, (self.base.get_id(),))
+
+ # Now put the raster name in the stds map register table
+ if dbmi.paramstyle == "qmark":
+ sql = "INSERT INTO " + stds_register_table + " (id) " + "VALUES (?)"
+ else:
+ sql = "INSERT INTO " + stds_register_table + " (id) " + "VALUES (%s)"
+ #print sql
+ dbif.cursor.execute(sql, (map_id,))
+
+ if connect == True:
+ dbif.close()
+
+ return True
+
+ def unregister_map(self, map, dbif = None):
+ """Unregister a map from the space time dataset.
+
+ This method takes care of the unregistration of a map
+ from a space time dataset.
+
+ @param map: The map object to unregister
+ @param dbif: The database interface to be used
+ """
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ if map.is_in_db(dbif) == False:
+ dbif.close()
+ core.fatal(_("Unable to find map <%s> in temporal database") % (map.get_id()))
+
+ core.verbose(_("Unregister %s map <%s>") % (map.get_type(), map.get_id()))
+
+ # First select all data from the database
+ map.select(dbif)
+ map_id = map.base.get_id()
+ map_register_table = map.get_stds_register()
+ stds_register_table = self.get_map_register()
+
+ # Check if the map is registered in the space time raster dataset
+ if dbmi.paramstyle == "qmark":
+ sql = "SELECT id FROM " + map_register_table + " WHERE id = ?"
+ else:
+ sql = "SELECT id FROM " + map_register_table + " WHERE id = %s"
+ dbif.cursor.execute(sql, (self.base.get_id(),))
+ row = dbif.cursor.fetchone()
+
+ # Break if the map is not registered
+ if row == None:
+ core.warning(_("Map <%s> is not registered in space time dataset") %(map_id, self.base.get_id()))
+ if connect == True:
+ dbif.close()
+ return False
+
+ # Remove the space time raster dataset from the raster dataset register
+ if map_register_table != None:
+ if dbmi.paramstyle == "qmark":
+ sql = "DELETE FROM " + map_register_table + " WHERE id = ?"
+ else:
+ sql = "DELETE FROM " + map_register_table + " WHERE id = %s"
+ dbif.cursor.execute(sql, (self.base.get_id(),))
+
+ # Remove the raster map from the space time raster dataset register
+ if stds_register_table != None:
+ if dbmi.paramstyle == "qmark":
+ sql = "DELETE FROM " + stds_register_table + " WHERE id = ?"
+ else:
+ sql = "DELETE FROM " + stds_register_table + " WHERE id = %s"
+ dbif.cursor.execute(sql, (map_id,))
+
+ if connect == True:
+ dbif.close()
+
+ def update_from_registered_maps(self, dbif = None):
+ """This methods updates the spatial and temporal extent as well as
+ type specific metadata. It should always been called after maps are registered
+ or unregistered/deleted from the space time dataset.
+
+ The update of the temporal extent checks if the end time is set correctly.
+ In case the registered maps have no valid end time (None) the maximum start time
+ will be used. If the end time is earlier than the maximum start time, it will
+ be replaced by the maximum start time.
+
+ An other solution to automate this is to use the diactivated trigger
+ in the SQL files. But this will result in a huge performance issue
+ in case many maps are registred (>1000).
+
+ @param dbif: The database interface to be used
+ """
+ core.verbose(_("Update metadata, spatial and temporal extent from all registered maps of <%s>") % (self.get_id()))
+
+ # Nothing to do if the register is not present
+ if not self.get_map_register():
+ return
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ map_time = None
+
+ use_start_time = False
+
+ # Get basic info
+ stds_name = self.base.get_name()
+ stds_mapset = self.base.get_mapset()
+ sql_path = get_sql_template_path()
+
+ #We create a transaction
+ sql_script = ""
+ sql_script += "BEGIN TRANSACTION;\n"
+
+ # Update the spatial and temporal extent from registered maps
+ # Read the SQL template
+ sql = open(os.path.join(sql_path, "update_stds_spatial_temporal_extent_template.sql"), 'r').read()
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ sql = sql.replace("SPACETIME_ID", self.base.get_id())
+ sql = sql.replace("STDS", self.get_type())
+
+ sql_script += sql
+ sql_script += "\n"
+
+ # Update type specific metadata
+ sql = open(os.path.join(sql_path, "update_" + self.get_type() + "_metadata_template.sql"), 'r').read()
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ sql = sql.replace("SPACETIME_ID", self.base.get_id())
+ sql = sql.replace("STDS", self.get_type())
+
+ sql_script += sql
+ sql_script += "\n"
+
+ sql_script += "END TRANSACTION;"
+
+ if dbmi.__name__ == "sqlite3":
+ dbif.cursor.executescript(sql_script)
+ else:
+ dbif.cursor.execute(sql_script)
+
+ # Read and validate the selected end time
+ self.select()
+
+ if self.is_time_absolute():
+ start_time, end_time, tz = self.get_absolute_time()
+ else:
+ start_time, end_time = self.get_relative_time()
+
+ # In case no end time is set, use the maximum start time of all registered maps as end time
+ if end_time == None:
+ use_start_time = True
+ else:
+ # Check if the end time is smaller than the maximum start time
+ if self.is_time_absolute():
+ sql = """SELECT max(start_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN
+ (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register);"""
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ else:
+ sql = """SELECT max(start_time) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
+ (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register);"""
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+
+ dbif.cursor.execute(sql)
+ row = dbif.cursor.fetchone()
+
+ if row != None:
+ # This seems to be a bug in sqlite3 Python driver
+ if dbmi.__name__ == "sqlite3":
+ tstring = row[0]
+ # Convert the unicode string into the datetime format
+ if tstring.find(":") > 0:
+ time_format = "%Y-%m-%d %H:%M:%S"
+ else:
+ time_format = "%Y-%m-%d"
+
+ max_start_time = datetime.strptime(tstring, time_format)
+ else:
+ max_start_time = row[0]
+
+ if end_time < max_start_time:
+ map_time = "mixed"
+ use_start_time = True
+ else:
+ map_time = "interval"
+
+ # Set the maximum start time as end time
+ if use_start_time:
+ if self.is_time_absolute():
+ sql = """UPDATE STDS_absolute_time SET end_time =
+ (SELECT max(start_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN
+ (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
+ ) WHERE id = 'SPACETIME_ID';"""
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ sql = sql.replace("SPACETIME_ID", self.base.get_id())
+ sql = sql.replace("STDS", self.get_type())
+ elif self.is_time_relative():
+ sql = """UPDATE STDS_relative_time SET end_time =
+ (SELECT max(start_time) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
+ (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
+ ) WHERE id = 'SPACETIME_ID';"""
+ sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
+ sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
+ sql = sql.replace("SPACETIME_ID", self.base.get_id())
+ sql = sql.replace("STDS", self.get_type())
+
+ if dbmi.__name__ == "sqlite3":
+ dbif.cursor.executescript(sql)
+ else:
+ dbif.cursor.execute(sql)
+
+ if end_time == None:
+ map_time = "point"
+
+ # Set the map time type
+ if self.is_time_absolute():
+ self.absolute_time.select(dbif)
+ self.metadata.select(dbif)
+ if self.metadata.get_number_of_maps() > 0:
+ self.absolute_time.set_map_time(map_time)
+ else:
+ self.absolute_time.set_map_time(None)
+ self.absolute_time.update_all(dbif)
+ else:
+ self.relative_time.select(dbif)
+ self.metadata.select(dbif)
+ if self.metadata.get_number_of_maps() > 0:
+ self.relative_time.set_map_time(map_time)
+ else:
+ self.relative_time.set_map_time(None)
+ self.relative_time.update_all(dbif)
+
+ # TODO: Compute the granularity of the dataset and update the database entry
+
+ if connect == True:
+ dbif.close()
Modified: grass/trunk/lib/python/temporal/space_time_datasets.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets.py 2011-10-12 07:04:50 UTC (rev 48747)
+++ grass/trunk/lib/python/temporal/space_time_datasets.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -26,7 +26,8 @@
import grass.script.vector as vector
import grass.script.raster3d as raster3d
from datetime_math import *
-from abstract_datasets import *
+from abstract_map_dataset import *
+from abstract_space_time_dataset import *
###############################################################################
@@ -372,347 +373,3 @@
self.spatial_extent = stvds_spatial_extent(ident=ident)
self.metadata = stvds_metadata(ident=ident)
-###############################################################################
-
-def register_maps_in_space_time_dataset(type, name, maps, start=None, increment=None, dbif = None, interval=False):
- """Use this method to register maps in space time datasets. This function is generic and
- can handle raster, vector and raster3d maps as well as there space time datasets.
-
- Additionally a start time string and an increment string can be specified
- to assign a time interval automatically to the maps.
-
- It takes care of the correct update of the space time datasets from all
- registered maps.
-
- @param type: The type of the maps raster, raster3d or vector
- @param name: The name of the space time dataset
- @param maps: A comma separated list of map names
- @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)
- @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
- @param dbif: The database interface to be used
- @param interval: If True, time intervals are created in case the start time and an increment is provided
- """
-
- # We may need the mapset
- mapset = core.gisenv()["MAPSET"]
-
- # Check if the dataset name contains the mapset as well
- if name.find("@") < 0:
- id = name + "@" + mapset
- else:
- id = name
-
- if type == "raster":
- sp = space_time_raster_dataset(id)
- if type == "raster3d":
- sp = space_time_raster3d_dataset(id)
- if type == "vector":
- sp = space_time_vector_dataset(id)
-
- connect = False
-
- if dbif == None:
- dbif = sql_database_interface()
- dbif.connect()
- connect = True
-
- # Read content from temporal database
- sp.select(dbif)
-
- if sp.is_in_db(dbif) == False:
- dbif.close()
- core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
-
- if maps.find(",") == -1:
- maplist = (maps,)
- else:
- maplist = tuple(maps.split(","))
-
- num_maps = len(maplist)
- count = 0
- for mapname in maplist:
- core.percent(count, num_maps, 1)
- mapname = mapname.strip()
- # Check if the map name contains the mapset as well
- if mapname.find("@") < 0:
- mapid = mapname + "@" + mapset
- else:
- mapid = mapname
- # Get a new instance of the space time dataset map type
- map = sp.get_new_map_instance(mapid)
-
- # In case the map is already registered print a message and continue to the next map
-
- # Put the map into the database
- if map.is_in_db(dbif) == False:
- # Break in case no valid time is provided
- if start == "" or start == None:
- dbif.close()
- 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
- 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
- map.insert(dbif)
- else:
- map.select(dbif)
- if map.get_temporal_type() != sp.get_temporal_type():
- dbif.close()
- core.fatal("Unable to register " + map.get_type() + " map <" + map.get_id() + ">. The temporal types are different.")
-
- # Set the valid time
- if start:
- assign_valid_time_to_map(ttype=sp.get_temporal_type(), map=map, start=start, end=None, increment=increment, mult=count, dbif=dbif, interval=interval)
-
- # Finally Register map in the space time dataset
- sp.register_map(map, dbif)
- count += 1
-
- # Update the space time tables
- sp.update_from_registered_maps(dbif)
-
- if connect == True:
- dbif.close()
-
- core.percent(num_maps, num_maps, 1)
-
-###############################################################################
-
-def unregister_maps_from_space_time_datasets(type, name, maps, dbif = None):
- """Unregister maps from a single space time dataset or, in case no dataset name is provided,
- unregister from all datasets within the maps are registered.
-
- @param type: The type of the maps raster, vector or raster3d
- @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.
- @param maps: A comma separated list of map names
- @param dbif: The database interface to be used
- """
- mapset = core.gisenv()["MAPSET"]
-
- if dbif == None:
- dbif = sql_database_interface()
- dbif.connect()
- connect = True
-
- # In case a space time dataset is specified
- if name:
- # Check if the dataset name contains the mapset as well
- if name.find("@") < 0:
- id = name + "@" + mapset
- else:
- id = name
-
- if type == "raster":
- sp = space_time_raster_dataset(id)
- if type == "raster3d":
- sp = space_time_raster3d_dataset(id)
- if type == "vector":
- sp = space_time_vector_dataset(id)
-
- if sp.is_in_db(dbif) == False:
- dbif.close()
- core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
-
- # Build the list of maps
- if maps.find(",") == -1:
- maplist = (maps,)
- else:
- maplist = tuple(maps.split(","))
-
- num_maps = len(maplist)
- count = 0
- for mapname in maplist:
- core.percent(count, num_maps, 1)
- mapname = mapname.strip()
- # Check if the map name contains the mapset as well
- if mapname.find("@") < 0:
- mapid = mapname + "@" + mapset
- else:
- mapid = mapname
-
- # Create a new instance with the map type
- if type == "raster":
- map = raster_dataset(mapid)
- if type == "raster3d":
- map = raster3d_dataset(mapid)
- if type == "vector":
- map = vector_dataset(mapid)
-
- # Unregister map if in database
- if map.is_in_db(dbif) == True:
- if name:
- sp.select(dbif)
- sp.unregister_map(map, dbif)
- else:
- map.select(dbif)
- map.unregister(dbif)
-
- count += 1
-
- if name:
- sp.update_from_registered_maps(dbif)
-
- if connect == True:
- dbif.close()
-
- core.percent(num_maps, num_maps, 1)
-
-###############################################################################
-
-def assign_valid_time_to_maps(type, maps, ttype, start, end=None, increment=None, dbif = None, interval=False):
- """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.
-
- @param type: The type of the maps raster, raster3d or vector
- @param maps: A comma separated list of map names
- @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)
- @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)
- @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
- @param dbif: The database interface to be used
- @param interval: If True, time intervals are created in case the start time and an increment is provided
- """
-
- if end and increment:
- if dbif:
- dbif.close()
- 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(","))
-
- num_maps = len(maplist)
- count = 0
-
- for mapname in maplist:
- core.percent(count, num_maps, 1)
- 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, interval=interval)
-
- 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()
-
- core.percent(num_maps, num_maps, 1)
-
-
-###############################################################################
-
-def assign_valid_time_to_map(ttype, map, start, end, increment=None, mult=1, dbif = None, interval=False):
- """Assign the valid time to a map dataset
-
- @param ttype: The temporal type which should be assigned and which the time format is of
- @param map: A map dataset object derived from abstract_map_dataset
- @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)
- @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)
- @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
- @param multi: A multiplier for the increment
- @param dbif: The database interface to use for sql queries
- @param interval: If True, time intervals are created in case the start time and an increment is provided
- """
-
- connect = False
-
- if dbif == None:
- dbif = sql_database_interface()
- dbif.connect()
- connect = True
-
- if ttype == "absolute":
- # Create the start time object
- if start.find(":") > 0:
- time_format = "%Y-%m-%d %H:%M:%S"
- else:
- time_format = "%Y-%m-%d"
-
- start_time = datetime.strptime(start, time_format)
- end_time = None
-
- if end:
- end_time = datetime.strptime(end, time_format)
-
- # Add the increment
- if increment:
- start_time = increment_datetime_by_string(start_time, increment, mult)
- if interval:
- end_time = increment_datetime_by_string(start_time, increment, 1)
-
- core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_id(), str(start_time), str(end_time)))
- map.update_absolute_time(start_time, end_time, None, dbif)
- else:
- start_time = float(start)
- end_time = None
-
- if end:
- end_time = float(end)
-
- if increment:
- start_time = start_time + mult * float(increment)
- if interval:
- end_time = start_time + float(increment)
-
- core.verbose(_("Set relative valid time for map <%s> to %f - %s") % (map.get_id(), start_time, str(end_time)))
- map.update_relative_time(start_time, end_time, dbif)
-
- if connect == True:
- dbif.close()
Added: grass/trunk/lib/python/temporal/space_time_datasets_tools.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets_tools.py (rev 0)
+++ grass/trunk/lib/python/temporal/space_time_datasets_tools.py 2011-10-12 09:38:16 UTC (rev 48748)
@@ -0,0 +1,370 @@
+"""!@package grass.temporal
+
+ at brief GRASS Python scripting module (temporal GIS functions)
+
+Temporal GIS related functions to be used in Python scripts.
+
+Usage:
+
+ at code
+import grass.temporal as tgis
+
+tgis.register_maps_in_space_time_dataset(type, name, maps)
+
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+
+from space_time_datasets import *
+
+###############################################################################
+
+def register_maps_in_space_time_dataset(type, name, maps, start=None, increment=None, dbif = None, interval=False):
+ """Use this method to register maps in space time datasets. This function is generic and
+ can handle raster, vector and raster3d maps as well as there space time datasets.
+
+ Additionally a start time string and an increment string can be specified
+ to assign a time interval automatically to the maps.
+
+ It takes care of the correct update of the space time datasets from all
+ registered maps.
+
+ @param type: The type of the maps raster, raster3d or vector
+ @param name: The name of the space time dataset
+ @param maps: A comma separated list of map names
+ @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)
+ @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
+ @param dbif: The database interface to be used
+ @param interval: If True, time intervals are created in case the start time and an increment is provided
+ """
+
+ # We may need the mapset
+ mapset = core.gisenv()["MAPSET"]
+
+ # Check if the dataset name contains the mapset as well
+ if name.find("@") < 0:
+ id = name + "@" + mapset
+ else:
+ id = name
+
+ if type == "raster":
+ sp = space_time_raster_dataset(id)
+ if type == "raster3d":
+ sp = space_time_raster3d_dataset(id)
+ if type == "vector":
+ sp = space_time_vector_dataset(id)
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ # Read content from temporal database
+ sp.select(dbif)
+
+ if sp.is_in_db(dbif) == False:
+ dbif.close()
+ core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
+
+ if maps.find(",") == -1:
+ maplist = (maps,)
+ else:
+ maplist = tuple(maps.split(","))
+
+ num_maps = len(maplist)
+ count = 0
+ for mapname in maplist:
+ core.percent(count, num_maps, 1)
+ mapname = mapname.strip()
+ # Check if the map name contains the mapset as well
+ if mapname.find("@") < 0:
+ mapid = mapname + "@" + mapset
+ else:
+ mapid = mapname
+ # Get a new instance of the space time dataset map type
+ map = sp.get_new_map_instance(mapid)
+
+ # In case the map is already registered print a message and continue to the next map
+
+ # Put the map into the database
+ if map.is_in_db(dbif) == False:
+ # Break in case no valid time is provided
+ if start == "" or start == None:
+ dbif.close()
+ 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
+ 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
+ map.insert(dbif)
+ else:
+ map.select(dbif)
+ if map.get_temporal_type() != sp.get_temporal_type():
+ dbif.close()
+ core.fatal("Unable to register " + map.get_type() + " map <" + map.get_id() + ">. The temporal types are different.")
+
+ # Set the valid time
+ if start:
+ assign_valid_time_to_map(ttype=sp.get_temporal_type(), map=map, start=start, end=None, increment=increment, mult=count, dbif=dbif, interval=interval)
+
+ # Finally Register map in the space time dataset
+ sp.register_map(map, dbif)
+ count += 1
+
+ # Update the space time tables
+ sp.update_from_registered_maps(dbif)
+
+ if connect == True:
+ dbif.close()
+
+ core.percent(num_maps, num_maps, 1)
+
+###############################################################################
+
+def unregister_maps_from_space_time_datasets(type, name, maps, dbif = None):
+ """Unregister maps from a single space time dataset or, in case no dataset name is provided,
+ unregister from all datasets within the maps are registered.
+
+ @param type: The type of the maps raster, vector or raster3d
+ @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.
+ @param maps: A comma separated list of map names
+ @param dbif: The database interface to be used
+ """
+ mapset = core.gisenv()["MAPSET"]
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ # In case a space time dataset is specified
+ if name:
+ # Check if the dataset name contains the mapset as well
+ if name.find("@") < 0:
+ id = name + "@" + mapset
+ else:
+ id = name
+
+ if type == "raster":
+ sp = space_time_raster_dataset(id)
+ if type == "raster3d":
+ sp = space_time_raster3d_dataset(id)
+ if type == "vector":
+ sp = space_time_vector_dataset(id)
+
+ if sp.is_in_db(dbif) == False:
+ dbif.close()
+ core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
+
+ # Build the list of maps
+ if maps.find(",") == -1:
+ maplist = (maps,)
+ else:
+ maplist = tuple(maps.split(","))
+
+ num_maps = len(maplist)
+ count = 0
+ for mapname in maplist:
+ core.percent(count, num_maps, 1)
+ mapname = mapname.strip()
+ # Check if the map name contains the mapset as well
+ if mapname.find("@") < 0:
+ mapid = mapname + "@" + mapset
+ else:
+ mapid = mapname
+
+ # Create a new instance with the map type
+ if type == "raster":
+ map = raster_dataset(mapid)
+ if type == "raster3d":
+ map = raster3d_dataset(mapid)
+ if type == "vector":
+ map = vector_dataset(mapid)
+
+ # Unregister map if in database
+ if map.is_in_db(dbif) == True:
+ if name:
+ sp.select(dbif)
+ sp.unregister_map(map, dbif)
+ else:
+ map.select(dbif)
+ map.unregister(dbif)
+
+ count += 1
+
+ if name:
+ sp.update_from_registered_maps(dbif)
+
+ if connect == True:
+ dbif.close()
+
+ core.percent(num_maps, num_maps, 1)
+
+###############################################################################
+
+def assign_valid_time_to_maps(type, maps, ttype, start, end=None, increment=None, dbif = None, interval=False):
+ """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.
+
+ @param type: The type of the maps raster, raster3d or vector
+ @param maps: A comma separated list of map names
+ @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)
+ @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)
+ @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
+ @param dbif: The database interface to be used
+ @param interval: If True, time intervals are created in case the start time and an increment is provided
+ """
+
+ if end and increment:
+ if dbif:
+ dbif.close()
+ 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(","))
+
+ num_maps = len(maplist)
+ count = 0
+
+ for mapname in maplist:
+ core.percent(count, num_maps, 1)
+ 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, interval=interval)
+
+ 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()
+
+ core.percent(num_maps, num_maps, 1)
+
+
+###############################################################################
+
+def assign_valid_time_to_map(ttype, map, start, end, increment=None, mult=1, dbif = None, interval=False):
+ """Assign the valid time to a map dataset
+
+ @param ttype: The temporal type which should be assigned and which the time format is of
+ @param map: A map dataset object derived from abstract_map_dataset
+ @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)
+ @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)
+ @param increment: Time increment between maps for time stamp creation (format absolute: NNN seconds, minutes, hours, days, weeks, months, years; format relative: 1.0)
+ @param multi: A multiplier for the increment
+ @param dbif: The database interface to use for sql queries
+ @param interval: If True, time intervals are created in case the start time and an increment is provided
+ """
+
+ connect = False
+
+ if dbif == None:
+ dbif = sql_database_interface()
+ dbif.connect()
+ connect = True
+
+ if ttype == "absolute":
+ # Create the start time object
+ if start.find(":") > 0:
+ time_format = "%Y-%m-%d %H:%M:%S"
+ else:
+ time_format = "%Y-%m-%d"
+
+ start_time = datetime.strptime(start, time_format)
+ end_time = None
+
+ if end:
+ end_time = datetime.strptime(end, time_format)
+
+ # Add the increment
+ if increment:
+ start_time = increment_datetime_by_string(start_time, increment, mult)
+ if interval:
+ end_time = increment_datetime_by_string(start_time, increment, 1)
+
+ core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_id(), str(start_time), str(end_time)))
+ map.update_absolute_time(start_time, end_time, None, dbif)
+ else:
+ start_time = float(start)
+ end_time = None
+
+ if end:
+ end_time = float(end)
+
+ if increment:
+ start_time = start_time + mult * float(increment)
+ if interval:
+ end_time = start_time + float(increment)
+
+ core.verbose(_("Set relative valid time for map <%s> to %f - %s") % (map.get_id(), start_time, str(end_time)))
+ map.update_relative_time(start_time, end_time, dbif)
+
+ if connect == True:
+ dbif.close()
More information about the grass-commit
mailing list