[GRASS-SVN] r51548 - in grass/trunk: lib/python lib/python/temporal raster temporal temporal/t.rast.aggregate temporal/t.rast.gapfill temporal/t.rast.mapcalc temporal/t.rast.series temporal/t.rast3d.mapcalc temporal/t.topology

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Apr 26 12:21:52 EDT 2012


Author: huhabla
Date: 2012-04-26 09:21:52 -0700 (Thu, 26 Apr 2012)
New Revision: 51548

Added:
   grass/trunk/temporal/t.rast.gapfill/
   grass/trunk/temporal/t.rast.gapfill/Makefile
   grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.html
   grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.py
   grass/trunk/temporal/t.rast.gapfill/test.t.rast.gapfill.sh
Modified:
   grass/trunk/lib/python/array.py
   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/base.py
   grass/trunk/lib/python/temporal/space_time_datasets.py
   grass/trunk/lib/python/temporal/spatial_extent.py
   grass/trunk/lib/python/temporal/temporal_relationships.py
   grass/trunk/lib/python/temporal/unit_tests.py
   grass/trunk/lib/python/temporal/univar_statistics.py
   grass/trunk/raster/Makefile
   grass/trunk/temporal/Makefile
   grass/trunk/temporal/t.rast.aggregate/t.rast.aggregate.py
   grass/trunk/temporal/t.rast.mapcalc/t.rast.mapcalc.py
   grass/trunk/temporal/t.rast.series/t.rast.series.py
   grass/trunk/temporal/t.rast3d.mapcalc/t.rast3d.mapcalc.py
   grass/trunk/temporal/t.topology/t.topology.py
Log:
New module to fill gaps in space time raster datasets using raster to raster interpolation of r.series.interp.
Keys for temporal sorting of dataset lists by start or end time.
Many new unit tests about sorting and temporal topology building.
Temporal topology computation.


Modified: grass/trunk/lib/python/array.py
===================================================================
--- grass/trunk/lib/python/array.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/array.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -7,6 +7,8 @@
 Usage:
 
 @code
+from grass.script import array as garray
+
     map = 'elevation'
     x = garray.array()
     x.read(map)

Modified: grass/trunk/lib/python/temporal/abstract_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_dataset.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/abstract_dataset.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -74,6 +74,15 @@
 	    self.relative_time.print_self()
 	self.spatial_extent.print_self()
 	self.metadata.print_self()
+	
+    def set_id(self, ident):
+	self.base.set_id(ident)
+	if self.is_time_absolute():
+	    self.absolute_time.set_id(ident)
+        if self.is_time_relative():
+	    self.relative_time.set_id(ident)
+	self.spatial_extent.set_id(ident)
+	self.metadata.set_id(ident)
 
     def get_id(self):
 	"""!Return the unique identifier of the dataset"""
@@ -325,3 +334,82 @@
 	    return self.relative_time.temporal_relation(map.relative_time)
     	return None
 
+###############################################################################
+	
+class abstract_dataset_comparison_key_start_time(object):
+    """!This comparison key can be used to sort lists of abstract datasets by start time
+    
+        Example:
+        
+        # Return all maps in a space time raster dataset as map objects
+	map_list = strds.get_registered_maps_as_objects()
+	
+	# Sort the maps in the list by start time
+	sorted_map_list = sorted(map_list, key=abstract_dataset_comparison_key_start_time)
+    """
+    def __init__(self, obj, *args):
+	self.obj = obj
+    def __lt__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA < startB
+    def __gt__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA > startB
+    def __eq__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA == startB
+    def __le__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA <= startB
+    def __ge__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA >= startB
+    def __ne__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return startA != startB
+	
+###############################################################################
+	
+class abstract_dataset_comparison_key_end_time(object):
+    """!This comparison key can be used to sort lists of abstract datasets by end time
+    
+        Example:
+        
+        # Return all maps in a space time raster dataset as map objects
+	map_list = strds.get_registered_maps_as_objects()
+	
+	# Sort the maps in the list by end time
+	sorted_map_list = sorted(map_list, key=abstract_dataset_comparison_key_end_time)
+    """
+    def __init__(self, obj, *args):
+	self.obj = obj
+    def __lt__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA < endB
+    def __gt__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA > endB
+    def __eq__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA == endB
+    def __le__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA <= endB
+    def __ge__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA >= endB
+    def __ne__(self, other):
+	startA, endA = self.obj.get_valid_time()
+	startB, endB = other.obj.get_valid_time()
+	return endA != endB
\ No newline at end of file

Modified: grass/trunk/lib/python/temporal/abstract_map_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_map_dataset.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/abstract_map_dataset.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -28,7 +28,7 @@
     
        This object will be set up by temporal topology creation methods.
        
-       If correctly initialize the calls get_next() and get_prev() let the user walk temporally forward
+       If correctly initialize the calls next() and prev() let the user walk temporally forward
        and backward in time.
        
        The following temporal relations with access methods are supported:
@@ -51,7 +51,7 @@
            for _map in dlist:
                _map.print_info()
                
-           start = start.get_next()       
+           start = start.next()       
     """
 
     def __init__(self):
@@ -81,7 +81,7 @@
 	   temporally located AFTER the start time of this map, but temporally 
 	   near than other maps of the same dataset.
 	   
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	"""
         self._temporal_topology["NEXT"] = _map
 
@@ -92,7 +92,7 @@
 	   temporally located BEFORE the start time of this map, but temporally 
 	   near than other maps of the same dataset.
 	   
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	"""
         self._temporal_topology["PREV"] = _map
 
@@ -119,7 +119,7 @@
     def append_equivalent(self, _map): 
 	"""!Append a map with equivalent temporal extent as this map
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	"""
         if not self._temporal_topology.has_key("EQUAL"):
             self._temporal_topology["EQUAL"] = []
@@ -137,7 +137,7 @@
     def append_overlaps(self, _map): 
 	"""!Append a map that this map temporally overlaps
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	"""
         if not self._temporal_topology.has_key("OVERLAPS"):
             self._temporal_topology["OVERLAPS"] = []
@@ -155,7 +155,7 @@
     def append_overlapped(self, _map): 
 	"""!Append a map that this map temporally overlapped
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	""" 
         if not self._temporal_topology.has_key("OVERLAPPED"):
             self._temporal_topology["OVERLAPPED"] = []
@@ -173,7 +173,7 @@
     def append_follows(self, _map): 
 	"""!Append a map that this map temporally follows
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	""" 
         if not self._temporal_topology.has_key("FOLLOWS"):
             self._temporal_topology["FOLLOWS"] = []
@@ -191,7 +191,7 @@
     def append_precedes(self, _map): 
 	"""!Append a map that this map temporally precedes
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	""" 
         if not self._temporal_topology.has_key("PRECEDES"):
             self._temporal_topology["PRECEDES"] = []
@@ -210,7 +210,7 @@
 	"""!Append a map that this map is temporally located during
 	   This includes temporal relationships starts and finishes
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	""" 
         if not self._temporal_topology.has_key("DURING"):
             self._temporal_topology["DURING"] = []
@@ -230,7 +230,7 @@
 	"""!Append a map that this map temporally contains
 	   This includes temporal relationships started and finished
 	
-	   @param _map This object should be of type abstract_map_dataset or derived classes
+	   @param _map: This object should be of type abstract_map_dataset or derived classes
 	""" 
         if not self._temporal_topology.has_key("CONTAINS"):
             self._temporal_topology["CONTAINS"] = []

Modified: grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -246,7 +246,7 @@
         """
 
         if maps == None:
-            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
             
         gaps = 0
 
@@ -259,7 +259,7 @@
 
         return gaps
         
-    def print_temporal_relation_matrix(self, maps=None, dbif=None):
+    def print_temporal_relationships(self, maps=None, dbif=None):
         """!Print the temporal relation matrix of all registered maps to stdout
 
            The temporal relation matrix includes the temporal relations between
@@ -270,26 +270,10 @@
         """
         
         if maps == None:
-            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
 	    
-	print_temporal_relations(maps, maps)
+	print_temporal_topology_relationships(maps, maps)
 
-    def get_temporal_relation_matrix(self, maps=None, dbif=None):
-        """!Return the temporal relation matrix of all registered maps as list of lists
-
-           The map list must be ordered by start time
-
-           The temporal relation matrix includes the temporal relations between
-           all registered maps. The relations are strings stored in a list of lists.
-           
-           @param maps: a ordered by start_time list of map objects
-           @param dbif: The database interface to be used
-        """
-        if maps == None:
-            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
-
-        return get_temporal_relation_matrix(maps, maps)
-
     def count_temporal_relations(self, maps=None, dbif=None):
         """!Count the temporal relations between the registered maps.
 
@@ -302,9 +286,9 @@
         """
         
         if maps == None:
-            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
 
-        return count_temporal_relations(maps, maps)
+        return count_temporal_topology_relationships(maps, maps)
 
     def check_temporal_topology(self, maps=None, dbif=None):
         """!Check the temporal topology
@@ -335,9 +319,9 @@
            @return True if topology is correct
         """
         if maps == None:
-            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
 
-        relations = self.count_temporal_relations(maps)
+        relations = count_temporal_topology_relationships(maps, maps)
 
         map_time = self.get_map_time()
 

Modified: grass/trunk/lib/python/temporal/base.py
===================================================================
--- grass/trunk/lib/python/temporal/base.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/base.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -438,6 +438,16 @@
         """
 	self.ident = ident
 	self.D["id"] = ident
+	
+        if ident != None:
+            if ident.find("@") >= 0:
+                name, mapset = ident.split("@")
+		self.set_mapset(mapset)
+            if name.find(":") >= 0:
+                name, layer = ident.split(":")
+		self.set_layer(layer)
+	    
+	    self.set_name(name)
 
     def set_name(self, name):
 	"""!Set the name of the dataset

Modified: grass/trunk/lib/python/temporal/space_time_datasets.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/space_time_datasets.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -27,6 +27,7 @@
 import grass.lib.raster as libraster
 import grass.lib.vector as libvector
 import grass.lib.raster3d as libraster3d
+import grass.script.array as garray
 
 from datetime_math import *
 from abstract_map_dataset import *
@@ -73,11 +74,30 @@
         """Return the two dimensional spatial relation"""
         
         return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
+        
+    def get_np_array(self):
+	"""Return this raster map as memmap numpy style array to access the raster
+	   values in numpy style without loading the whole map in the RAM. 
+	   
+	   In case this raster map does exists in the grass spatial database, the map
+	   will be exported using r.out.bin to a temporary location and assigned to the
+	   memmap object that is returned by this function.
+	   
+	   In case the raster map does not exists, an empty temporary binary file will be created
+	   and assigned to the memap object.
+	   
+	   You need to call the write function to write the memmap array back into grass.
+	"""
 	
+	a = garray.array()
+	
+	if self.map_exists():
+	    a.read(self.get_map_id())
+	
+	return a
+	
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = raster_base(ident=ident)
 	self.absolute_time = raster_absolute_time(ident=ident)
 	self.relative_time = raster_relative_time(ident=ident)
@@ -210,9 +230,6 @@
 
 
         # Fill base information
-
-        self.base.set_name(self.ident.split("@")[0])
-        self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
 
         # Get the data from an existing raster map
@@ -289,8 +306,6 @@
         
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = raster3d_base(ident=ident)
 	self.absolute_time = raster3d_absolute_time(ident=ident)
 	self.relative_time = raster3d_relative_time(ident=ident)
@@ -421,8 +436,6 @@
         """!Load all info from an existing raster3d map into the internal structure"""
 
         # Fill base information
-        self.base.set_name(self.ident.split("@")[0])
-        self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
 
         # Fill spatial extent
@@ -502,8 +515,6 @@
 	
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = vector_base(ident=ident)
 	self.absolute_time = vector_absolute_time(ident=ident)
 	self.relative_time = vector_relative_time(ident=ident)
@@ -648,12 +659,6 @@
 
 
         # Fill base information
-	if self.ident.find(":") >= 0:
-	    self.base.set_name(self.ident.split("@")[0].split(":")[0])
-	    self.base.set_layer(self.ident.split("@")[0].split(":")[1])
-	else:
-	    self.base.set_name(self.ident.split("@")[0])
-        self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
 
         # Get the data from an existing raster map
@@ -719,13 +724,7 @@
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = strds_base(ident=ident)
-
-        if ident != None:
-            self.base.set_name(self.ident.split("@")[0])
-            self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
         self.absolute_time = strds_absolute_time(ident=ident)
         self.relative_time = strds_relative_time(ident=ident)
@@ -779,13 +778,7 @@
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = str3ds_base(ident=ident)
-
-        if ident != None:
-            self.base.set_name(self.ident.split("@")[0])
-            self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
         self.absolute_time = str3ds_absolute_time(ident=ident)
         self.relative_time = str3ds_relative_time(ident=ident)
@@ -833,13 +826,7 @@
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.ident = ident
-
 	self.base = stvds_base(ident=ident)
-
-        if ident != None:
-            self.base.set_name(self.ident.split("@")[0])
-            self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
         self.absolute_time = stvds_absolute_time(ident=ident)
         self.relative_time = stvds_relative_time(ident=ident)

Modified: grass/trunk/lib/python/temporal/spatial_extent.py
===================================================================
--- grass/trunk/lib/python/temporal/spatial_extent.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/spatial_extent.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -23,7 +23,7 @@
 from base import *
 
 class spatial_extent(sql_database_interface):
-    """!This is the spatial extent base class for all maps and spacetime datasets"""
+    """!This is the spatial extent base class for all maps and space time datasets"""
     def __init__(self, table=None, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, proj="XY"):
 
 	sql_database_interface.__init__(self, table, ident)
@@ -61,16 +61,16 @@
                 E -= 360.0
                 W -= 360.0
                 
-        if(self.get_north() < S):
+        if(self.get_north() <= S):
             return False
         
-        if(self.get_south() > N):
+        if(self.get_south() >= N):
             return False
             
-        if self.get_east() < W:
+        if self.get_east() <= W:
             return False
         
-        if self.get_west() > E:
+        if self.get_west() >= E:
             return False
         
         return True
@@ -92,10 +92,10 @@
         T = extent.get_top()
         B = extent.get_bottom()
         
-        if self.get_top() < B:
+        if self.get_top() <= B:
             return False
         
-        if self.get_bottom() > T:
+        if self.get_bottom() >= T:
             return False
         
         return True
@@ -678,7 +678,7 @@
 	return True
 
     def meet(self,extent):
-	""" Check if self and extent touch meet other in three dimensions"""
+	""" Check if self and extent meet other in three dimensions"""
 	eN = extent.get_north()
         eS = extent.get_south()
         eE = extent.get_east()
@@ -727,7 +727,7 @@
 	    edge = "B"
 	    edge_count += 1	
 	
-	# Meet a a single edge only
+	# Meet a single edge only
 	if edge_count != 1:
 	    return False
 	

Modified: grass/trunk/lib/python/temporal/temporal_relationships.py
===================================================================
--- grass/trunk/lib/python/temporal/temporal_relationships.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/temporal_relationships.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -23,8 +23,10 @@
 from abstract_map_dataset import *
 from datetime_math import *
 
+###############################################################################
+
 class temporal_topology_builder(object):
-    """!This class is designed to build the temporal topology based on a list of maps
+    """!This class is designed to build the temporal topology based on a lists of maps
     
 	Example:
 	
@@ -34,7 +36,7 @@
 	
 	# Now lets build the temporal topology of the maps in the list
 	tb = temporal_topology_builder()
-	tb.build(maps, True)
+	tb.build(maps)
 	
 	for _map in tb:
 	    _map.print_temporal_topology_info()
@@ -63,6 +65,7 @@
     def _reset(self):
         self._store = {}
         self._first = None
+        self._temporal_iteratable = False
 
     def _set_first(self, first):
         self._first = first
@@ -84,8 +87,117 @@
 	   @return The map with the earliest start time
 	"""
 	return self._first
+
+    def _build_internal_iteratable(self, maps):
+	"""!Build an iteratable temporal topology structure for all maps in the list and store the maps internally
 	
-    def build(self, maps, is_sorted = False):
+	   Basically the "next" and "prev" relations will be set in the temporal topology structure of each map
+	   The maps will be added to the object, so they can be accessed using the iterator of this class
+	   
+	   @param maps: A sorted (by start_time)list of abstract_dataset objects with initiated temporal extent
+	"""
+	self._build_iteratable(maps)
+
+	for _map in maps:
+	    self._insert(_map)
+	
+	# Detect the first map
+	self._detect_first()
+	
+    def _build_iteratable(self, maps):
+	"""!Build an iteratable temporal topology structure for all maps in the list
+	
+	   Basically the "next" and "prev" relations will be set in the temporal topology structure of each map.
+	   
+	   @param maps: A sorted (by start_time)list of abstract_dataset objects with initiated temporal extent
+	"""
+	for i in xrange(len(maps)):
+	    offset = i + 1
+	    for j in xrange(offset, len(maps)):		
+		# Get the temporal relationship
+		relation = maps[j].temporal_relation(maps[i])
+		
+		# Build the next reference
+		if relation != "equivalent" and relation != "started":
+		    maps[i].set_next(maps[j])
+		    break
+		
+	for _map in maps:
+	    _next = _map.next()
+	    if _next:
+		_next.set_prev(_map)
+	    _map.set_temporal_topology_build_true()
+	
+    def build2(self, mapsA, mapsB):
+	"""!Build the temporal topology structure between two ordered lists of maps
+	
+	   This method builds the temporal topology from mapsA to mapsB and vice verse.
+	   The temporal topology structure of each map, defined in class temporal_map_relations,
+	   will be reseted and rebuild for mapsA and mapsB. 
+	   
+	   After building the temporal topology the modified map objects of mapsA can be accessed 
+	   in the same way as a dictionary using there id. The implemented iterator assures 
+	   the chronological iteration over the mapsA.	    
+	   
+	   @param mapsA: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
+	   @param mapsB: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
+	"""
+	
+	if mapsA == mapsB:
+	    self.build(mapsA, True)
+	    return
+	
+	for _map in mapsA:
+	    _map.reset_temporal_topology()
+	    
+	for _map in mapsB:
+	    _map.reset_temporal_topology()
+	
+	for i in xrange(len(mapsA)):
+	    for j in xrange(len(mapsB)):
+		
+		# Get the temporal relationship
+		relation = mapsB[j].temporal_relation(mapsA[i])
+		
+		if relation == "before":
+		    continue
+			    
+		if relation == "equivalent":
+		    mapsB[j].append_equivalent(mapsA[i])
+		    mapsA[i].append_equivalent(mapsB[j])
+		elif relation == "follows":
+		    mapsB[j].append_follows(mapsA[i])
+		    mapsA[i].append_precedes(mapsB[j])
+		elif relation == "precedes":
+		    mapsB[j].append_precedes(mapsA[i])
+		    mapsA[i].append_follows(mapsB[j])
+		elif relation == "during" or relation == "starts" or relation == "finishes":
+		    mapsB[j].append_during(mapsA[i])
+		    mapsA[i].append_contains(mapsB[j])
+		elif relation == "contains" or relation == "started" or relation == "finished":
+		    mapsB[j].append_contains(mapsA[i])
+		    mapsA[i].append_during(mapsB[j])
+		elif relation == "overlaps":
+		    mapsB[j].append_overlaps(mapsA[i])
+		    mapsA[i].append_overlapped(mapsB[j])
+		elif relation == "overlapped":
+		    mapsB[j].append_overlapped(mapsA[i])
+		    mapsA[i].append_overlaps(mapsB[j])
+
+		# Break if the next map follows and the over-next maps is after
+		if relation == "follows":
+		    if j < len(mapsB) - 1:
+			relation = mapsB[j + 1].temporal_relation(mapsA[i])
+			if relation == "after":
+			    break
+		# Break if the the next map is after
+		if relation == "after":
+		    break 
+	
+	self._build_internal_iteratable(mapsA)
+	self._build_iteratable(mapsB)
+			    
+    def build(self, maps):
 	"""!Build the temporal topology structure
 	
 	   This method builds the temporal topology based on all maps in the provided map list.
@@ -94,58 +206,19 @@
 	   
 	   After building the temporal topology the modified map objects can be accessed 
 	   in the same way as a dictionary using there id. The implemented iterator assures 
-	   the chronological iteration over the maps.
+	   the chronological iteration over the maps.	   
 	   
-	   
-	   @param maps: A list of abstract_dataset objects with initiated temporal extent
-	   @param is_sorted Set to True if the map list is sorted by start time, sorting will dramatically reduce computation time
+	   @param maps: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
 	"""
 	for _map in maps:
 	    _map.reset_temporal_topology()
 	
 	for i in xrange(len(maps)):
-	    if is_sorted:
-		offset = i + 1
-		found_next = False
-	    else:
-		offset = 0
-		# Needed for "next" computation 
-		start0, end0 = maps[i].get_valid_time()
-	    
+	    offset = i + 1
 	    for j in xrange(offset, len(maps)):
 		
-		# Do not build topology of the same maps
-		if maps[i] == maps[j]:
-		    continue
-		
 		# Get the temporal relationship
 		relation = maps[j].temporal_relation(maps[i])
-		
-		# We can skip several relationships if not sorted
-		if not is_sorted:
-		    if relation == "before":
-			continue
-		    if relation == "precedes":
-			continue
-		    if relation == "overlapped":
-			continue
-		    if relation == "finished":
-			continue
-		
-		# Build the next reference
-		if is_sorted:
-		    if not found_next and relation != "equivalent" and relation != "started":
-			maps[i].set_next(maps[j])
-			found_next = True
-		else: 
-		    start2, end2 = maps[j].get_valid_time()
-		    if maps[i].next():
-			start1, end1 = maps[i].next().get_valid_time()
-			if start2 > start0 and start2 < start1:
-			    maps[i].set_next(maps[j])
-		    else:
-			if start2 > start0:
-			    maps[i].set_next(maps[j])
 			    
 		# The start time of map j is equal or later than map i
 		if relation == "equivalent":
@@ -174,23 +247,14 @@
 		# Break if the the next map is after
 		if relation == "after":
 		    break 
+		    
+	self._build_internal_iteratable(maps)
 	
-	# Build the previous pointer and store the map internally
-	for _map in maps:
-	    _next = _map.next()
-	    if _next:
-		_next.set_prev(_map)
-	    _map.set_temporal_topology_build_true()
-	    self._insert(_map)
-	
-	# Detect the first map
-	self._detect_first()
-	
     def __iter__(self):
-        _start = self._first
-        while _start != None:
-            yield _start
-            _start = _start.next()
+	_start = self._first
+	while _start != None:
+	    yield _start
+	    _start = _start.next()
 
     def __getitem__(self, index):
         return self._store[index.get_id()]
@@ -202,12 +266,14 @@
         return _map in self._store.values()
 
 
-def print_temporal_relations(maps1, maps2):
+###############################################################################
+
+def print_temporal_topology_relationships(maps1, maps2):
     """!Print the temporal relation matrix of the temporal ordered map lists maps1 and maps2
        to stdout.
 	
-	@param maps1: a ordered by start_time list of map objects with initiated temporal extent
-	@param maps2: a ordered by start_time list of map objects with initiated temporal extent
+	@param maps1: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
+	@param maps2: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
     """
     
     identical = False
@@ -240,60 +306,16 @@
 	    if relation == "after":
 		break
 
-def get_temporal_relation_matrix(maps1, maps2):
-    """!Return the temporal relation matrix of two map lists
+###############################################################################
 
-	Booth map lists must be ordered by start time
-
-	The temporal relationship matrix includes the temporal relations between
-	the two map lists. Returned is a nested dict representing 
-	a sparse (upper right side in case maps1 == maps2) relationship matrix.
-	
-	@param maps1: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
-	@param maps2: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
-    """
-
-    matrix = {}
-    identical = False
-    
-    if maps1 == maps2:
-	identical = True
-
-    for i in range(len(maps1)):
-	if identical == True:
-	    start = i + 1
-	else:
-	    start = 0
-	    
-	row = {}
-	    
-	for j in range(start, len(maps2)):
-	    relation = maps1[j].temporal_relation(maps2[i])
-
-	    row[maps2[j].base.get_id()] = relation 
-
-	    # Break if the last map follows
-	    if relation == "follows":
-		if j < len(maps1) - 1:
-		    relation = maps1[j + 1].temporal_relation(maps2[i])
-		    if relation == "after":
-			break
-	    # Break if the the next map is after
-	    if relation == "after":
-		break
-
-	matrix[maps1[i].base.get_id()] = row
-
-    return matrix
-
-def count_temporal_relations(maps1, maps2):
+def count_temporal_topology_relationships(maps1, maps2):
     """!Count the temporal relations between the two lists of maps
 
 	The map lists must be ordered by start time. Temporal relations are counted 
 	by analyzing the sparse (upper right side in case maps1 == maps2) temporal relationships matrix.
 
-	@param maps1: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
-	@param maps2: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
+	@param maps1: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
+	@param maps2: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
 	@return A dictionary with counted temporal relationships
     """
     
@@ -330,4 +352,3 @@
 		break  
 
     return tcount
-

Modified: grass/trunk/lib/python/temporal/unit_tests.py
===================================================================
--- grass/trunk/lib/python/temporal/unit_tests.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/unit_tests.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -20,12 +20,16 @@
 
 @author Soeren Gebbert
 """
+import copy
 from datetime import datetime, date, time, timedelta
 import grass.script.core as core
 from temporal_granularity import *
 from datetime_math import *
 from space_time_datasets import *
 
+# Uncomment this to detect the error
+#core.set_raise_on_error(True)
+
 ###############################################################################
 
 def test_increment_datetime_by_string():
@@ -44,7 +48,7 @@
     delta = dt1 -dt2
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("increment computation is wrong %s" % (delta))
+        core.fatal("increment computation is wrong %s" % (delta))
 
     # Second test
     print "# Test 2"
@@ -60,7 +64,7 @@
     delta = dt1 -dt2
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("increment computation is wrong %s" % (delta))
+        core.fatal("increment computation is wrong %s" % (delta))
 
     # Third test
     print "# Test 3"
@@ -76,7 +80,7 @@
     delta = dt1 -dt2
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("increment computation is wrong %s" % (delta))
+        core.fatal("increment computation is wrong %s" % (delta))
 
     # 4. test
     print "# Test 4"
@@ -92,7 +96,7 @@
     delta = dt1 -dt2
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("increment computation is wrong %s" % (delta))
+        core.fatal("increment computation is wrong %s" % (delta))
 
 ###############################################################################
 
@@ -107,7 +111,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # Second test
     print "Test 2"
@@ -117,7 +121,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # Third test
     print "Test 2"
@@ -127,7 +131,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 4. test
     print "Test 4"
@@ -137,7 +141,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 5. test
     print "Test 5"
@@ -147,7 +151,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 6. test
     print "Test 6"
@@ -157,7 +161,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 7. test
     print "Test 7"
@@ -167,7 +171,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 8. test
     print "Test 8"
@@ -177,7 +181,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 9. test
     print "Test 9"
@@ -187,7 +191,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 10. test
     print "Test 10"
@@ -197,7 +201,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
     # 11. test
     print "Test 11"
@@ -207,7 +211,7 @@
     delta = correct - result 
 
     if delta.days != 0 or delta.seconds != 0:
-        core.error("Granularity adjustment computation is wrong %s" % (delta))
+        core.fatal("Granularity adjustment computation is wrong %s" % (delta))
 
 ###############################################################################
 
@@ -225,7 +229,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 2"
     start = datetime(2001, 1, 1, 00,00,14)
@@ -239,7 +243,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 3"
     start = datetime(2001, 1, 1, 00,00,44)
@@ -253,7 +257,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 4"
     start = datetime(2001, 1, 1, 00,00,30)
@@ -267,7 +271,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 5"
     start = datetime(2001, 1, 1, 00,00,00)
@@ -281,7 +285,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 6"
     start = datetime(2011,10,31, 00,45,00)
@@ -295,7 +299,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 7"
     start = datetime(2011,10,31, 00,45,00)
@@ -309,7 +313,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 8"
     start = datetime(2011,10,31, 00,45,00)
@@ -323,7 +327,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 9"
     start = datetime(2011,10,31, 00,00,00)
@@ -337,7 +341,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 10"
     start = datetime(2011,10,31, 00,00,00)
@@ -351,7 +355,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 11"
     start = datetime(2011,10,31, 12,00,00)
@@ -365,7 +369,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 12"
     start = datetime(2011,11,01, 00,00,00)
@@ -379,7 +383,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
 
     print "Test 13"
@@ -394,7 +398,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 14"
     start = datetime(2011,10,06, 00,00,00)
@@ -408,7 +412,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 15"
     start = datetime(2011,12,02, 00,00,00)
@@ -422,7 +426,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 16"
     start = datetime(2011,01,01, 00,00,00)
@@ -436,7 +440,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 17"
     start = datetime(2011,12,01, 00,00,00)
@@ -450,7 +454,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 18"
     start = datetime(2011,12,01, 00,00,00)
@@ -464,7 +468,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 19"
     start = datetime(2011,06,01, 00,00,00)
@@ -478,7 +482,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 20"
     start = datetime(2011,06,01, 00,00,00)
@@ -493,7 +497,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 21"
     start = datetime(2011,06,01, 00,00,00)
@@ -508,7 +512,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 22"
     start = datetime(2011,06,01, 00,00,00)
@@ -523,7 +527,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 23"
     start = datetime(2011,06,01, 00,00,00)
@@ -538,7 +542,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
     print "Test 24"
     start = datetime(2011,06,01, 00,00,00)
@@ -553,7 +557,7 @@
     delta = correct - result 
 
     if delta != 0:
-        core.error("Compute datetime delta is wrong %s" % (delta))
+        core.fatal("Compute datetime delta is wrong %s" % (delta))
 
 ###############################################################################
 
@@ -577,7 +581,7 @@
     fact = fact - 1
     gran = round(compute_relative_time_granularity(maps))
     if fact - gran != 0:
-        core.error("Wrong granularity reference %i != gran %i" % (fact, gran))
+        core.fatal("Wrong granularity reference %i != gran %i" % (fact, gran))
  
     print "Test 2"
     maps = []
@@ -594,7 +598,7 @@
     fact = fact - 1
     gran = round(compute_relative_time_granularity(maps) * 86400)
     if fact - gran != 0:
-        core.error("Wrong granularity reference %i != gran %i" % (fact, gran))
+        core.fatal("Wrong granularity reference %i != gran %i" % (fact, gran))
 
     print "Test 3 with gaps"
     maps = []
@@ -612,7 +616,7 @@
 
     gran = round(compute_relative_time_granularity(maps))
     if fact - gran != 0:
-        core.error("Wrong granularity reference %i != gran %i" % (fact, gran))
+        core.fatal("Wrong granularity reference %i != gran %i" % (fact, gran))
 
     # Second we test intervals and points mixed
 
@@ -636,7 +640,7 @@
     fact = fact - 1
     gran = round(compute_relative_time_granularity(maps))
     if fact - gran != 0:
-        core.error("Wrong granularity reference %i != gran %i" % (fact, gran))
+        core.fatal("Wrong granularity reference %i != gran %i" % (fact, gran))
  
     # Second we test points only
  
@@ -652,7 +656,7 @@
 
     gran = round(compute_relative_time_granularity(maps) * 86400)
     if fact - gran != 0:
-        core.error("Wrong granularity reference %i != gran %i" % (fact, gran))
+        core.fatal("Wrong granularity reference %i != gran %i" % (fact, gran))
 
 ###############################################################################
 
@@ -674,7 +678,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 2"
     maps = []
@@ -689,7 +693,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 3"
     maps = []
@@ -704,7 +708,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 4"
     maps = []
@@ -719,7 +723,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 3"
     maps = []
@@ -734,7 +738,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 4"
     maps = []
@@ -749,7 +753,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 5"
     maps = []
@@ -765,7 +769,7 @@
     increment = "1 days"
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 6"
     maps = []
@@ -781,7 +785,7 @@
     increment = "25 hours"
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 7"
     maps = []
@@ -796,7 +800,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 8"
     maps = []
@@ -811,7 +815,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 9"
     maps = []
@@ -827,7 +831,7 @@
     increment = "325 minutes"
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 10"
     maps = []
@@ -843,7 +847,7 @@
     increment = "330 seconds"
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 11"
     maps = []
@@ -859,7 +863,7 @@
     increment = "3630 seconds"
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 12"
     maps = []
@@ -874,7 +878,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     # Test absolute time points    
 
@@ -891,7 +895,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 14"
     maps = []
@@ -906,7 +910,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 15"
     maps = []
@@ -921,7 +925,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     # Test absolute time interval and points    
 
@@ -947,7 +951,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
     print "Test 17"
     maps = []
@@ -971,7 +975,7 @@
 
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
-        core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+        core.fatal("Wrong granularity reference %s != gran %s" % (increment, gran))
 
 ###############################################################################
 
@@ -988,7 +992,7 @@
     if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
        C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
        C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
-        core.error("Wrong intersection computation")
+        core.fatal("Wrong intersection computation")
         
     B = spatial_extent(north=40, south=30, east=60, west=10, bottom=-50, top=50)
     B.print_info()
@@ -998,7 +1002,7 @@
     if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
        C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
        C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
-        core.error("Wrong intersection computation")
+        core.fatal("Wrong intersection computation")
         
     B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-50, top=50)
     B.print_info()
@@ -1008,7 +1012,7 @@
     if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
        C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
        C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
-        core.error("Wrong intersection computation")
+        core.fatal("Wrong intersection computation")
     
     B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-30, top=50)
     B.print_info()
@@ -1018,7 +1022,7 @@
     if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
        C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
        C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
-        core.error("Wrong intersection computation")
+        core.fatal("Wrong intersection computation")
     
     B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-30, top=30)
     B.print_info()
@@ -1028,7 +1032,7 @@
     if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
        C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
        C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
-        core.error("Wrong intersection computation")
+        core.fatal("Wrong intersection computation")
 
 ###############################################################################
 
@@ -1043,7 +1047,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "equivalent":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     B = spatial_extent(north=70, south=20, east=60, west=10, bottom=-50, top=50)
     B.print_info()
@@ -1051,12 +1055,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=60, west=10, bottom=-50, top=50)
     B.print_info()
@@ -1064,22 +1068,22 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = B.spatial_relation_2d(A)
     print relation
     if relation!= "covered":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = B.spatial_relation(A)
     print relation
     if relation!= "covered":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=50, west=10, bottom=-50, top=50)
     B.print_info()
@@ -1087,24 +1091,24 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = B.spatial_relation_2d(A)
     print relation
     if relation!= "covered":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
     
     relation = B.spatial_relation(A)
     print relation
     if relation!= "covered":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
     B.print_info()
@@ -1112,12 +1116,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "contain":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-40, top=50)
     B.print_info()
@@ -1125,7 +1129,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "cover":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-40, top=40)
     B.print_info()
@@ -1133,12 +1137,12 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "contain":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = B.spatial_relation(A)
     print relation
     if relation!= "in":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=90, south=30, east=50, west=20, bottom=-40, top=40)
     B.print_info()
@@ -1146,12 +1150,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "overlap":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "overlap":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-40, top=40)
     A.print_info()
@@ -1160,12 +1164,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "in":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
     
     relation = A.spatial_relation(B)
     print relation
     if relation!= "overlap":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-40, top=60)
     A.print_info()
@@ -1174,7 +1178,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "overlap":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
 	
     B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-60, top=60)
@@ -1184,7 +1188,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "in":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     A = spatial_extent(north=80, south=60, east=60, west=10, bottom=-50, top=50)
     A.print_info()
@@ -1194,12 +1198,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     A = spatial_extent(north=60, south=40, east=60, west=10, bottom=-50, top=50)
     A.print_info()
@@ -1209,12 +1213,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=40, bottom=-50, top=50)
     A.print_info()
@@ -1224,12 +1228,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1239,12 +1243,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1254,12 +1258,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1269,12 +1273,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1284,12 +1288,12 @@
     relation = A.spatial_relation_2d(B)
     print relation
     if relation!= "disjoint":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
 	
     relation = A.spatial_relation(B)
     print relation
     if relation!= "disjoint":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1299,7 +1303,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
     A.print_info()
@@ -1309,7 +1313,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
     A.print_info()
@@ -1319,7 +1323,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
     A.print_info()
@@ -1329,7 +1333,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
     A.print_info()
@@ -1339,7 +1343,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
     A.print_info()
@@ -1349,7 +1353,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
     A.print_info()
@@ -1359,7 +1363,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  ###
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
@@ -1370,7 +1374,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
     A.print_info()
@@ -1380,7 +1384,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
     A.print_info()
@@ -1390,7 +1394,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
     A.print_info()
@@ -1400,7 +1404,7 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
+	core.fatal("Wrong spatial relation: %s"%(relation))
  
     A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
     A.print_info()
@@ -1410,77 +1414,159 @@
     relation = A.spatial_relation(B)
     print relation
     if relation!= "meet":
-	core.error("Wrong spatial relation: %s"%(relation))
-	
+	core.fatal("Wrong spatial relation: %s"%(relation))
+
+###############################################################################
+
 def test_temporal_topology_builder():
-    map_list = []
-    count = 0
-    for year in xrange(0,1):
-	for month in xrange(1,6):
-	    start = datetime(2001 + year, month, 01)
-	    end = datetime(2001 + year, month + 1, 01)
-	    _map = raster_dataset("%d at A"%(count))
-	    _map.set_absolute_time(start, end)
-	    map_list.append(_map)
-	    count += 1
+    map_listA = []
+    
+    _map = raster_dataset(ident = "1 at a")
+    _map.set_absolute_time(datetime(2001, 01, 01), datetime(2001, 02, 01))
+    map_listA.append(copy.copy(_map))
+    _map = raster_dataset(ident = "2 at a")
+    _map.set_absolute_time(datetime(2001, 02, 01), datetime(2001, 03, 01))
+    map_listA.append(copy.copy(_map))
+    _map = raster_dataset(ident = "3 at a")
+    _map.set_absolute_time(datetime(2001, 03, 01), datetime(2001, 04, 01))
+    map_listA.append(copy.copy(_map))
+    _map = raster_dataset(ident = "4 at a")
+    _map.set_absolute_time(datetime(2001, 04, 01), datetime(2001, 05, 01))
+    map_listA.append(copy.copy(_map))
+    _map = raster_dataset(ident = "5 at a")
+    _map.set_absolute_time(datetime(2001, 05, 01), datetime(2001, 06, 01))
+    map_listA.append(copy.copy(_map))
 
     tb = temporal_topology_builder()
-    tb.build(map_list, True)
+    tb.build(map_listA)
 
+    count = 0
     for _map in tb:
-	_map.print_info()
- 
-    map_list = []
-    for year in xrange(0,1):
-	for month in xrange(1,6):
-	    start = datetime(2001 + year, month, 01)
-	    end = datetime(2001 + year, month + 1, 01)
-	    _map = raster_dataset("%d at A"%(count))
-	    _map.set_absolute_time(start, end)
-	    map_list.append(_map)
-	    count += 1
-	    
-	    start = datetime(2001 + year, month, 14)
-	    end = datetime(2001 + year, month + 1, 14)
-	    _map = raster_dataset("%d at A"%(count))
-	    _map.set_absolute_time(start, end)
-	    map_list.append(_map)
-	    count += 1
-	    
-	    start = datetime(2001 + year, month, 8)
-	    end = datetime(2001 + year, month + 1, 21)
-	    _map = raster_dataset("%d at A"%(count))
-	    _map.set_absolute_time(start, end)
-	    map_list.append(_map)
-	    count += 1
+	print "[%s]"%(_map.get_name())
+	_map.print_temporal_topology_info()
+	if _map.get_id() != map_listA[count].get_id():
+	    core.fatal("Error building temporal topology <%s> != <%s>"%( _map.get_id(), map_listA[count].get_id()))
+	count += 1
+	
+    map_listB = []
+        
+    _map = raster_dataset(ident = "1 at b")
+    _map.set_absolute_time(datetime(2001, 01, 14), datetime(2001, 03, 14))
+    map_listB.append(copy.copy(_map))
+    _map = raster_dataset(ident = "2 at b")
+    _map.set_absolute_time(datetime(2001, 02, 01), datetime(2001, 04, 01))
+    map_listB.append(copy.copy(_map))
+    _map = raster_dataset(ident = "3 at b")
+    _map.set_absolute_time(datetime(2001, 02, 14), datetime(2001, 04, 30))
+    map_listB.append(copy.copy(_map))
+    _map = raster_dataset(ident = "4 at b")
+    _map.set_absolute_time(datetime(2001, 04, 02), datetime(2001, 04, 30))
+    map_listB.append(copy.copy(_map))
+    _map = raster_dataset(ident = "5 at b")
+    _map.set_absolute_time(datetime(2001, 05, 01), datetime(2001, 05, 14))
+    map_listB.append(copy.copy(_map))
+    
+    tb = temporal_topology_builder()
+    tb.build(map_listB)
 
-    tb = temporal_topology_builder()
-    tb.build(map_list, False)
+    # Probing some relations
+    if map_listB[0].get_overlapped()[0] != map_listB[1]:
+	    core.fatal("Error building temporal topology")
+    if map_listB[0].get_overlapped()[1] != map_listB[2]:
+	    core.fatal("Error building temporal topology")
+    if map_listB[2].get_contains()[0] != map_listB[3]:
+	    core.fatal("Error building temporal topology")
+    if map_listB[3].get_during()[0] != map_listB[2]:
+	    core.fatal("Error building temporal topology")
+    
+    count = 0
     for _map in tb:
+	print "[%s]"%(_map.get_map_id
+	())
+	_map.print_temporal_topology_shell_info()
+	if _map.get_id() != map_listB[count].get_id():
+	    core.fatal("Error building temporal topology <%s> != <%s>"%( _map.get_id(), map_listB[count].get_id()))
+	count += 1
 	
-	print _map.get_id()
-	_map.absolute_time.print_info()
-	_map.print_temporal_topology_info()
-	
-    # Test the performance of many overlapping maps
+    tb = temporal_topology_builder()
+    tb.build2(map_listA, map_listB)
+    
     count = 0
-    for year in xrange(0,200):
-	for month in xrange(1,12):
-	    start = datetime(1901 + year, month, 01)
-	    end = datetime(1904 + year, month + 1, 01)
-	    _map = raster_dataset("%d at A"%(count))
-	    _map.set_absolute_time(start, end)
-	    map_list.append(_map)
-	    count += 1
+    for _map in tb:
+	print "[%s]"%(_map.get_map_id())
+	_map.print_temporal_topology_shell_info()
+	if _map.get_id() != map_listA[count].get_id():
+	    core.fatal("Error building temporal topology <%s> != <%s>"%( _map.get_id(), map_listA[count].get_id()))
+	count += 1
+
+    count = 0
+    for _map in map_listB:
+	print "[%s]"%(_map.get_map_id())
+	_map.print_temporal_topology_shell_info()
+
+    # Probing some relations
+    if map_listA[3].get_follows()[0] != map_listB[1]:
+	    core.fatal("Error building temporal topology")   
+    if map_listA[3].get_precedes()[0] != map_listB[4]:
+	    core.fatal("Error building temporal topology")
+    if map_listA[3].get_overlaps()[0] != map_listB[2]:
+	    core.fatal("Error building temporal topology")
+    if map_listA[3].get_contains()[0] != map_listB[3]:
+	    core.fatal("Error building temporal topology")
 	    
-    print "Build temporal topology with sorting for %i maps"%count
-    tb = temporal_topology_builder()
-    tb.build(map_list, True)
+    if map_listA[2].get_during()[0] != map_listB[1]:
+	    core.fatal("Error building temporal topology")
+    if map_listA[2].get_during()[1] != map_listB[2]:
+	    core.fatal("Error building temporal topology")
+
+
+###############################################################################
+
+def test_map_list_sorting():
+    
+    map_list = []
+    
+    _map = raster_dataset(ident = "1 at a")
+    _map.set_absolute_time(datetime(2001, 02, 01), datetime(2001, 03, 01))
+    map_list.append(copy.copy(_map))
+    _map = raster_dataset(ident = "2 at a")
+    _map.set_absolute_time(datetime(2001, 01, 01), datetime(2001, 02, 01))
+    map_list.append(copy.copy(_map))
+    _map = raster_dataset(ident = "3 at a")
+    _map.set_absolute_time(datetime(2001, 03, 01), datetime(2001, 04, 01))
+    map_list.append(copy.copy(_map))
+	    
+    print "Original"
+    for _map in map_list:
+	print _map.get_valid_time()[0],  _map.get_valid_time()[1]
+    print "Sorted by start time"
+    new_list = sorted(map_list, key=abstract_dataset_comparison_key_start_time)
+    for _map in new_list:
+	print _map.get_valid_time()[0],  _map.get_valid_time()[1]
 	
-    print "Build temporal topology without sorting for %i maps"%count
-    tb = temporal_topology_builder()
-    tb.build(map_list, False)
     
+    if new_list[0] != map_list[1]:
+	core.fatal("Sorting by start time failed")
+    if new_list[1] != map_list[0]:
+	core.fatal("Sorting by start time failed")
+    if new_list[2] != map_list[2]:
+	core.fatal("Sorting by start time failed")
+	
+    print "Sorted by end time"
+    new_list = sorted(map_list, key=abstract_dataset_comparison_key_end_time)
+    for _map in new_list:
+	print _map.get_valid_time()[0],  _map.get_valid_time()[1]
+	
+
+    if new_list[0] != map_list[1]:
+	core.fatal("Sorting by end time failed")
+    if new_list[1] != map_list[0]:
+	core.fatal("Sorting by end time failed")
+    if new_list[2] != map_list[2]:
+	core.fatal("Sorting by end time failed")
+
+###############################################################################
+
 if __name__ == "__main__":
     test_increment_datetime_by_string()
     test_adjust_datetime_to_granularity()
@@ -1490,4 +1576,6 @@
     test_compute_datetime_delta()
     test_spatial_extent_intersection()
     test_spatial_relations()
-    test_temporal_topology_builder()
\ No newline at end of file
+    test_temporal_topology_builder()
+    test_map_list_sorting()
+    
\ No newline at end of file

Modified: grass/trunk/lib/python/temporal/univar_statistics.py
===================================================================
--- grass/trunk/lib/python/temporal/univar_statistics.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/lib/python/temporal/univar_statistics.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -101,7 +101,7 @@
 ###############################################################################
     
 def print_vector_dataset_univar_statistics(input, twhere, layer, type, column, where, extended, header, fs):
-    """!Print univariate statistics for a space time raster or raster3d dataset
+    """!Print univariate statistics for a space time vector dataset
     
        @param input The name of the space time dataset
        @param twhere A temporal database where statement

Modified: grass/trunk/raster/Makefile
===================================================================
--- grass/trunk/raster/Makefile	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/raster/Makefile	2012-04-26 16:21:52 UTC (rev 51548)
@@ -86,6 +86,7 @@
 	r.rescale.eq \
 	r.ros \
 	r.series \
+	r.series.interp \
 	r.slope.aspect \
 	r.solute.transport \
 	r.spread \

Modified: grass/trunk/temporal/Makefile
===================================================================
--- grass/trunk/temporal/Makefile	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/Makefile	2012-04-26 16:21:52 UTC (rev 51548)
@@ -20,6 +20,7 @@
 	t.rast.export \
 	t.rast.out.vtk \
 	t.rast.import \
+	t.rast.gapfill \
 	t.rast.extract \
 	t.rast3d.list \
 	t.rast3d.extract \

Modified: grass/trunk/temporal/t.rast.aggregate/t.rast.aggregate.py
===================================================================
--- grass/trunk/temporal/t.rast.aggregate/t.rast.aggregate.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/t.rast.aggregate/t.rast.aggregate.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -58,15 +58,6 @@
 #%option G_OPT_R_BASE
 #%end
 
-#%option
-#% key: nprocs
-#% type: integer
-#% description: The number of r.mapcalc processes to run in parallel
-#% required: no
-#% multiple: no
-#% answer: 2
-#%end
-
 #%flag
 #% key: n
 #% description: Register Null maps
@@ -89,7 +80,6 @@
     register_null = flags["n"]
     method = options["method"]
     sampling = options["sampling"]
-    nprocs = int(options["nprocs"])
 
     # Make sure the temporal database exists
     tgis.create_temporal_database()

Added: grass/trunk/temporal/t.rast.gapfill/Makefile
===================================================================
--- grass/trunk/temporal/t.rast.gapfill/Makefile	                        (rev 0)
+++ grass/trunk/temporal/t.rast.gapfill/Makefile	2012-04-26 16:21:52 UTC (rev 51548)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../
+
+PGM = t.rast.gapfill
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script $(TEST_DST)

Added: grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.html
===================================================================
Added: grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.py
===================================================================
--- grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.py	                        (rev 0)
+++ grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:	t.rast.gapfill
+# AUTHOR(S):	Soeren Gebbert
+#
+# PURPOSE:	Replace gaps in a space time raster dataset with interpolated raster maps.
+# COPYRIGHT:	(C) 2012 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: Replace gaps in a space time raster dataset with interpolated raster maps.
+#% keywords: temporal
+#% keywords: interpolation
+#%end
+
+#%option G_OPT_STRDS_INPUT
+#%end
+
+#%option G_OPT_T_WHERE
+#%end
+
+#%option
+#% key: base
+#% type: string
+#% description: The base name of the interpolated raster maps. This name will be extended with a numerical prefix
+#% required: yes
+#% multiple: no
+#%end
+
+#%option
+#% key: nprocs
+#% type: integer
+#% description: The number of interpolation processes to run in parallel
+#% required: no
+#% multiple: no
+#% answer: 1
+#%end
+
+#%flag
+#% key: t
+#% description: Assign the space time raster dataset start and end time to the output map
+#%end
+
+from multiprocessing import Process
+import grass.script as grass
+import grass.temporal as tgis
+
+############################################################################
+
+    
+def main():
+
+    # Get the options
+    input = options["input"]
+    base = options["base"]
+    where = options["where"]
+    nprocs = options["nprocs"]
+
+    # Make sure the temporal database exists
+    tgis.create_temporal_database()
+
+    if input.find("@") >= 0:
+        id = input
+    else:
+        mapset =  grass.gisenv()["MAPSET"]
+        id = input + "@" + mapset
+
+    # We need a database interface
+    dbif = tgis.sql_database_interface_connection()
+    dbif.connect()
+    
+    sp = tgis.space_time_raster_dataset(id)
+
+    if sp.is_in_db(dbif) == False:
+        grass.fatal(_("Space time %s dataset <%s> not found") % (sp.get_new_map_instance(None).get_type(), id))
+
+    sp.select(dbif)
+    
+    maps = sp.get_registered_maps_as_objects_with_gaps(where, dbif)
+
+    num = len(maps)
+    
+    gap_list = []
+    
+    # Identify all gaps and create new names
+    count = 0
+    for _map in maps:
+	if _map.get_id() == None:
+	    count += 1
+	    _id = "%s_%d@%s"%(base, num + count, mapset)
+	    print _id
+	    _map.set_id(_id)
+	    if _map.map_exists() or _map.is_in_db(dbif):
+		grass.fatal(_("Map with name <%s> already exists. Please use another base name."%(_id)))
+	    
+	    gap_list.append(_map)
+	    
+    if len(gap_list) == 0:
+	grass.message(_("No gaps found"))
+	return
+
+    # Build the temporal topology
+    tb = tgis.temporal_topology_builder()
+    tb.build(maps)
+    
+    # Do some checks before computation
+    for _map in gap_list:	
+	if not _map.get_precedes() or not _map.get_follows():
+	    grass.fatal(_("Unable to determine successor and predecessor of a gap."))
+	
+	if len(_map.get_precedes()) > 1:
+	    grass.warning(_("More than one successor of the gap found. Using the first found."))
+	    
+	if len(_map.get_follows()) > 1:
+	    grass.warning(_("More than one predecessor of the gap found. Using the first found."))
+
+    # Interpolate the maps using parallel processing   
+    proc_list = []
+    proc_count = 0
+    num = len(gap_list)
+        
+    for _map in gap_list:	
+	predecessor = _map.get_follows()[0]
+	successor = _map.get_precedes()[0]
+	
+	# Build the module inputs strings
+	inputs = "%s,%s"%(predecessor.get_map_id(), successor.get_map_id())
+	dpos = "0,1"
+	output = "%s"%(_map.get_name())
+	outpos = "0.5"
+	
+	# Start several processes in parallel
+	proc_list.append(Process(target=run_interp, args=(inputs,dpos,output,outpos)))
+	proc_list[proc_count].start()
+	proc_count += 1
+	
+	if proc_count == nprocs or proc_count == num:
+	    proc_count = 0
+	    exitcodes = 0
+	    for proc in proc_list:
+		proc.join()
+		exitcodes += proc.exitcode
+		
+	    if exitcodes != 0:
+		dbif.close()
+		grass.fatal(_("Error while interpolation computation"))
+		
+	    # Empty process list
+	    proc_list = []
+
+    # Insert new interpolated maps in temporal database and dataset
+    for _map in gap_list:
+	_map.load()
+	_map.insert(dbif)
+	sp.register_map(_map, dbif)
+	
+    sp.update_from_registered_maps(dbif)
+    dbif.close()
+	
+###############################################################################
+
+def run_interp(inputs, dpos, output, outpos):
+    """Helper function to run r.series.interp in parallel"""
+    return grass.run_command("r.series.interp", input=inputs, datapos=dpos, output=output, samplingpos=outpos, overwrite=grass.overwrite(), quiet=True)
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    main()
+


Property changes on: grass/trunk/temporal/t.rast.gapfill/t.rast.gapfill.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass/trunk/temporal/t.rast.gapfill/test.t.rast.gapfill.sh
===================================================================
--- grass/trunk/temporal/t.rast.gapfill/test.t.rast.gapfill.sh	                        (rev 0)
+++ grass/trunk/temporal/t.rast.gapfill/test.t.rast.gapfill.sh	2012-04-26 16:21:52 UTC (rev 51548)
@@ -0,0 +1,32 @@
+# We need to set a specific region in the
+# @preprocess step of this test. 
+# 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 = 100"
+r.mapcalc --o expr="prec_2 = 300"
+r.mapcalc --o expr="prec_3 = 500"
+
+n1=`g.tempfile pid=1 -d` 
+
+cat > "${n1}" << EOF
+prec_1|2001-01-01|2001-02-01
+prec_2|2001-03-01|2001-04-01
+prec_3|2001-05-01|2001-06-01
+EOF
+
+t.create --v --o type=strds temporaltype=absolute output=precip_abs title="A test" descr="A test"
+t.register --v type=rast input=precip_abs file=${n1}
+
+# @test
+t.rast.gapfill input=precip_abs base="prec" nprocs=2
+t.info precip_abs
+
+t.info type=rast input=prec_6
+t.info type=rast input=prec_7
+
+# @postprocess
+
+t.unregister --v type=rast maps=prec_1,prec_2,prec_3,prec_6,prec_7
+t.remove --v type=strds input=precip_abs
+g.remove rast=prec_1,prec_2,prec_3,prec_6,prec_7


Property changes on: grass/trunk/temporal/t.rast.gapfill/test.t.rast.gapfill.sh
___________________________________________________________________
Added: svn:executable
   + *

Modified: grass/trunk/temporal/t.rast.mapcalc/t.rast.mapcalc.py
===================================================================
--- grass/trunk/temporal/t.rast.mapcalc/t.rast.mapcalc.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/t.rast.mapcalc/t.rast.mapcalc.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -39,8 +39,12 @@
 #%option G_OPT_STRDS_OUTPUT
 #%end
 
-#%option G_OPT_R_BASE
+#%option
+#% key: base
+#% type: string
+#% description: The base name of the new created raster maps. This name will be extended with a numerical prefix
 #% required: yes
+#% multiple: no
 #%end
 
 #%option

Modified: grass/trunk/temporal/t.rast.series/t.rast.series.py
===================================================================
--- grass/trunk/temporal/t.rast.series/t.rast.series.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/t.rast.series/t.rast.series.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -26,7 +26,7 @@
 #%option
 #% key: method
 #% type: string
-#% description: Aggregate operation to be peformed on the raster maps
+#% description: Aggregate operation to be performed on the raster maps
 #% required: yes
 #% multiple: no
 #% options: average,count,median,mode,minimum,min_raster,maximum,max_raster,stddev,range,sum,variance,diversity,slope,offset,detcoeff,quart1,quart3,perc90,quantile,skewness,kurtosis

Modified: grass/trunk/temporal/t.rast3d.mapcalc/t.rast3d.mapcalc.py
===================================================================
--- grass/trunk/temporal/t.rast3d.mapcalc/t.rast3d.mapcalc.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/t.rast3d.mapcalc/t.rast3d.mapcalc.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -39,10 +39,12 @@
 #%option G_OPT_STR3DS_OUTPUT
 #%end
 
-#%option G_OPT_R_BASE
+#%option
+#% key: base
+#% type: string
+#% description: The base name of the new created 3d raster maps. This name will be extended with a numerical prefix
 #% required: yes
-#% description: Name of the base raster3d map
-#% gisprompt: old,grid3,3d-raster
+#% multiple: no
 #%end
 
 #%option

Modified: grass/trunk/temporal/t.topology/t.topology.py
===================================================================
--- grass/trunk/temporal/t.topology/t.topology.py	2012-04-26 14:35:48 UTC (rev 51547)
+++ grass/trunk/temporal/t.topology/t.topology.py	2012-04-26 16:21:52 UTC (rev 51548)
@@ -69,7 +69,7 @@
     maps = sp.get_registered_maps_as_objects(where=where, order="start_time", dbif=None)
 
     if tmatrix:
-        matrix = sp.print_temporal_relation_matrix(maps)
+        sp.print_temporal_relationships(maps)
         return
 
     sp.base.print_info()



More information about the grass-commit mailing list