[GRASS-SVN] r54821 - in grass/trunk: lib/python/temporal temporal/t.rast.mapcalc

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Jan 30 14:01:00 PST 2013


Author: huhabla
Date: 2013-01-30 14:01:00 -0800 (Wed, 30 Jan 2013)
New Revision: 54821

Added:
   grass/trunk/temporal/t.rast.mapcalc/test.t.rast.mapcalc.operators.sh
Modified:
   grass/trunk/lib/python/temporal/mapcalc.py
   grass/trunk/lib/python/temporal/space_time_datasets_tools.py
Log:
Introduction of temporal operators in t.rast.mapcalc


Modified: grass/trunk/lib/python/temporal/mapcalc.py
===================================================================
--- grass/trunk/lib/python/temporal/mapcalc.py	2013-01-30 16:34:51 UTC (rev 54820)
+++ grass/trunk/lib/python/temporal/mapcalc.py	2013-01-30 22:01:00 UTC (rev 54821)
@@ -24,9 +24,41 @@
        raster/raster3d datasets, using a specific sampling method 
        to select temporal related maps.
 
-       A mapcalc expression can be provided to process the temporal 
-       extracted maps.
-       Mapcalc expressions are supported for raster and raster3d maps.
+       A mapcalc expression must be provided to process the temporal 
+       selected maps. Temporal operators are available in addition to 
+       the r.mapcalc operators:
+       
+       Supported operators for relative and absolute time:
+       * td() - the time delta of the current interval in days 
+         and fractions of days or the unit in case of relative time
+       * start_time() - The start time of the interval from the begin of the time 
+         series in days and fractions of days or the unit in case of relative time
+       * end_time() - The end time of the current interval from the begin of the time 
+         series in days and fractions of days or the unit in case of relative time
+         
+       Supported operators for absolute time:
+       * start_doy() - Day of year (doy) from the start time [1 - 366]
+       * start_dow() - Day of week (dow) from the start time [1 - 7], 
+         the start of the week is monday == 1
+       * start_year() - The year of the start time [0 - 9999]
+       * start_month() - The month of the start time [1 - 12]
+       * start_week() - Week of year of the start time [1 - 54]
+       * start_day() - Day of month from the start time [1 - 31]
+       * start_hour() - The hour of the start time [0 - 23]
+       * start_minute() - The minute of the start time [0 - 59]
+       * start_second() - The second of the start time [0 - 59]
+       
+       * end_doy() - Day of year (doy) from the start time [1 - 366]
+       * end_dow() - Day of week (dow) from the end time [1 - 7], 
+         end is monday == 1
+       * end_year() - The year of the end time [0 - 9999]
+       * end_month() - The month of the end time [1 - 12]
+       * end_woy() - Week of year (woy) of the end time [1 - 54]
+       * end_day() - Day of month from the start time [1 - 31]
+       * end_hour() - The hour of the end time [0 - 23]
+       * end_minute() - The minute of the end time [0 - 59]
+       * end_second() - The second of the end time [0 - 59]
+       
 
        @param input The name of the input space time raster/raster3d dataset
        @param output The name of the extracted new space time raster(3d) dataset
@@ -207,8 +239,10 @@
 
             # Create the r.mapcalc statement for the current time step
             map_name = "%s_%i" % (base, count)
-            expr = "%s = %s" % (map_name, expression)
-
+            expr = "%s=%s" % (map_name, expression)
+            # Remove spaces and new lines
+            expr = expr.replace(" ", "")
+            
             # Check that all maps are in the sample
             valid_maps = True
             # Replace all dataset names with their map names of the 
@@ -248,6 +282,9 @@
             else:
                 start, end, unit = sample_map_list[i].get_relative_time()
                 new_map.set_relative_time(start, end, unit)
+            
+            # Parse the temporal expressions
+            expr = _operator_parser(expr,  sample_map_list[0],  sample_map_list[i])
 
             map_list.append(new_map)
 
@@ -255,9 +292,9 @@
             core.verbose(_("Apply mapcalc expression: \"%s\"") % expr)
 
             if type == "raster":
-                proc_list.append(Process(target=run_mapcalc2d, args=(expr,)))
+                proc_list.append(Process(target=_run_mapcalc2d, args=(expr,)))
             else:
-                proc_list.append(Process(target=run_mapcalc3d, args=(expr,)))
+                proc_list.append(Process(target=_run_mapcalc3d, args=(expr,)))
             proc_list[proc_count].start()
             proc_count += 1
 
@@ -342,15 +379,274 @@
 
 ###############################################################################
 
-def run_mapcalc2d(expr):
+def _run_mapcalc2d(expr):
     """Helper function to run r.mapcalc in parallel"""
     return core.run_command("r.mapcalc", expression=expr, 
                             overwrite=core.overwrite(), quiet=True)
 
 ###############################################################################
 
-
-def run_mapcalc3d(expr):
+def _run_mapcalc3d(expr):
     """Helper function to run r3.mapcalc in parallel"""
     return core.run_command("r3.mapcalc", expression=expr, 
                             overwrite=core.overwrite(), quiet=True)
+
+###############################################################################
+
+def _operator_parser(expr, first, current):
+    """This method parses the expression string and substitutes 
+       the temporal operators with numerical values.
+       
+       Supported operators for relative and absolute time are:
+       * td() - the time delta of the current interval in days 
+         and fractions of days or the unit in case of relative time
+       * start_time() - The start time of the interval from the begin of the time 
+         series in days and fractions of days or the unit in case of relative time
+       * end_time() - The end time of the current interval from the begin of the time 
+         series in days and fractions of days or the unit in case of relative time
+         
+       Supported operators for absolute time:
+       * start_doy() - Day of year (doy) from the start time [1 - 366]
+       * start_dow() - Day of week (dow) from the start time [1 - 7], 
+         the start of the week is monday == 1
+       * start_year() - The year of the start time [0 - 9999]
+       * start_month() - The month of the start time [1 - 12]
+       * start_week() - Week of year of the start time [1 - 54]
+       * start_day() - Day of month from the start time [1 - 31]
+       * start_hour() - The hour of the start time [0 - 23]
+       * start_minute() - The minute of the start time [0 - 59]
+       * start_second() - The second of the start time [0 - 59]
+       
+       * end_doy() - Day of year (doy) from the start time [1 - 366]
+       * end_dow() - Day of week (dow) from the end time [1 - 7], 
+         end is monday == 1
+       * end_year() - The year of the end time [0 - 9999]
+       * end_month() - The month of the end time [1 - 12]
+       * end_woy() - Week of year (woy) of the end time [1 - 54]
+       * end_day() - Day of month from the start time [1 - 31]
+       * end_hour() - The hour of the end time [0 - 23]
+       * end_minute() - The minute of the end time [0 - 59]
+       * end_second() - The second of the end time [0 - 59]
+       
+       The modified expression is returned.
+       
+    """
+    is_time_absolute = first.is_time_absolute()
+    
+    expr = _parse_td_operator(expr, is_time_absolute, first, current)
+    expr = _parse_start_time_operator(expr, is_time_absolute, first, current)
+    expr = _parse_end_time_operator(expr, is_time_absolute, first, current)
+    expr = _parse_start_operators(expr, is_time_absolute, current)
+    expr = _parse_end_operators(expr, is_time_absolute, current)
+    
+    return expr
+
+###############################################################################
+
+def _parse_start_operators(expr, is_time_absolute, current):
+    """
+       Supported operators for absolute time:
+       * start_doy() - Day of year (doy) from the start time [1 - 366]
+       * start_dow() - Day of week (dow) from the start time [1 - 7], 
+         the start of the week is monday == 1
+       * start_year() - The year of the start time [0 - 9999]
+       * start_month() - The month of the start time [1 - 12]
+       * start_week() - Week of year of the start time [1 - 54]
+       * start_day() - Day of month from the start time [1 - 31]
+       * start_hour() - The hour of the start time [0 - 23]
+       * start_minute() - The minute of the start time [0 - 59]
+       * start_second() - The second of the start time [0 - 59]
+    """
+    
+    if not is_time_absolute:
+        core.fatal(_("The temporal operators <%s> supports only absolute time."%("start_*")))
+    
+    start, end, tz = current.get_absolute_time()
+        
+    if expr.find("start_year()") >= 0:
+        expr = expr.replace("start_year()", str(start.year))
+        
+    if expr.find("start_month()") >= 0:
+        expr = expr.replace("start_month()", str(start.month))
+        
+    if expr.find("start_week()") >= 0:
+        expr = expr.replace("start_week()", str(start.isocalendar()[1]))
+        
+    if expr.find("start_day()") >= 0:
+        expr = expr.replace("start_day()", str(start.day))
+        
+    if expr.find("start_hour()") >= 0:
+        expr = expr.replace("start_hour()", str(start.hour))
+        
+    if expr.find("start_minute()") >= 0:
+        expr = expr.replace("start_minute()", str(start.minute))
+        
+    if expr.find("start_second()") >= 0:
+        expr = expr.replace("start_second()", str(start.second))
+        
+    if expr.find("start_dow()") >= 0:
+        expr = expr.replace("start_dow()", str(start.isoweekday()))
+        
+    if expr.find("start_doy()") >= 0:        
+        year = datetime(start.year, 1, 1)
+        delta = start - year
+        
+        expr = expr.replace("start_doy()", str(delta.days + 1))
+        
+    return expr
+
+###############################################################################
+
+def _parse_end_operators(expr, is_time_absolute, current):
+    """
+       Supported operators for absolute time:
+       * end_doy() - Day of year (doy) from the end time [1 - 366]
+       * end_dow() - Day of week (dow) from the end time [1 - 7], 
+         the end of the week is monday == 1
+       * end_year() - The year of the end time [0 - 9999]
+       * end_month() - The month of the end time [1 - 12]
+       * end_week() - Week of year of the end time [1 - 54]
+       * end_day() - Day of month from the end time [1 - 31]
+       * end_hour() - The hour of the end time [0 - 23]
+       * end_minute() - The minute of the end time [0 - 59]
+       * end_second() - The minute of the end time [0 - 59]
+       
+       In case of time instances the end_* expression will be replaced by null()
+    """
+    
+    if not is_time_absolute:
+        core.fatal(_("The temporal operators <%s> supports only absolute time."%("end_*")))
+    
+    start, end, tz = current.get_absolute_time()
+        
+    if expr.find("end_year()") >= 0:
+        if not end:
+            expr = expr.replace("end_year()", "null()")
+        else:
+            expr = expr.replace("end_year()", str(end.year))
+        
+    if expr.find("end_month()") >= 0:
+        if not end:
+            expr = expr.replace("end_month()", "null()")
+        else:
+            expr = expr.replace("end_month()", str(end.month))
+        
+    if expr.find("end_week()") >= 0:
+        if not end:
+            expr = expr.replace("end_week()", "null()")
+        else:
+            expr = expr.replace("end_week()", str(end.isocalendar()[1]))
+        
+    if expr.find("end_day()") >= 0:
+        if not end:
+            expr = expr.replace("end_day()", "null()")
+        else:
+            expr = expr.replace("end_day()", str(end.day))
+        
+    if expr.find("end_hour()") >= 0:
+        if not end:
+            expr = expr.replace("end_hour()", "null()")
+        else:
+            expr = expr.replace("end_hour()", str(end.hour))
+        
+    if expr.find("end_minute()") >= 0:
+        if not end:
+            expr = expr.replace("end_minute()", "null()")
+        else:
+            expr = expr.replace("end_minute()", str(end.minute))
+        
+    if expr.find("end_second()") >= 0:
+        if not end:
+            expr = expr.replace("end_second()", "null()")
+        else:
+            expr = expr.replace("end_second()", str(end.second))
+        
+    if expr.find("end_dow()") >= 0:
+        if not end:
+            expr = expr.replace("end_dow()", "null()")
+        else:
+            expr = expr.replace("end_dow()", str(end.isoweekday()))
+        
+    if expr.find("end_doy()") >= 0:
+        if not end:
+            expr = expr.replace("end_doy()", "null()")
+        else:
+            year = datetime(end.year, 1, 1)
+            delta = end - year
+            
+            expr = expr.replace("end_doy()", str(delta.days + 1))
+        
+    return expr
+
+###############################################################################
+
+def _parse_td_operator(expr, is_time_absolute, first, current):
+    """Parse the time delta operator td(). This operator
+       represents the size of the current time interval
+       in days and fraction of days for absolute time,
+       and in relative units in case of relative time.
+       
+       In case of time instances, the td() operator will be of type null(). 
+    """
+    if expr.find("td()") >= 0:
+        td = "null()"
+        if is_time_absolute:
+            start, end, tz = current.get_absolute_time()
+            if end != None:
+                td = time_delta_to_relative_time(end - start)
+        else:
+            start, end, unit = current.get_relative_time()
+            if end != None:
+                td = end - start
+        expr = expr.replace("td()", str(td))
+        
+    return expr
+
+###############################################################################
+
+def _parse_start_time_operator(expr, is_time_absolute, first, current):
+    """Parse the start_time() operator. This operator represent 
+    the time difference between the start time of the sample space time
+    raster dataset and the start time of the current interval or instance. The time
+    is measured  in days and fraction of days for absolute time,
+    and in relative units in case of relative time."""
+    if expr.find("start_time()") >= 0:
+        if is_time_absolute:
+            start1, end, tz = first.get_absolute_time()
+            start, end, tz = current.get_absolute_time()
+            x = time_delta_to_relative_time(start - start1)
+        else:
+            start1, end, unit = first.get_relative_time()
+            start, end, unit = current.get_relative_time()
+            x = start - start1
+        expr = expr.replace("start_time()", str(x))
+        
+    return expr
+
+###############################################################################
+
+def _parse_end_time_operator(expr, is_time_absolute, first, current):
+    """Parse the end_time() operator. This operator represent 
+    the time difference between the start time of the sample space time
+    raster dataset and the start time of the current interval. The time
+    is measured  in days and fraction of days for absolute time,
+    and in relative units in case of relative time.
+    
+    The end_time() will be represented by null() in case of a time instance.
+    """
+    if expr.find("end_time()") >= 0:
+        x = "null()"
+        if is_time_absolute:
+            start1, end, tz = first.get_absolute_time()
+            start, end, tz = current.get_absolute_time()
+            if end:
+                x = time_delta_to_relative_time(end - start1)
+        else:
+            start1, end, unit = first.get_relative_time()
+            start, end, unit = current.get_relative_time()
+            if end:
+                x = end - start1
+        expr = expr.replace("end_time()", str(x))
+        
+    return expr
+

Modified: grass/trunk/lib/python/temporal/space_time_datasets_tools.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets_tools.py	2013-01-30 16:34:51 UTC (rev 54820)
+++ grass/trunk/lib/python/temporal/space_time_datasets_tools.py	2013-01-30 22:01:00 UTC (rev 54821)
@@ -666,7 +666,7 @@
 
     for st in sts:
         if st.is_in_db(dbif) == False:
-            core.fatal(_("Dataset <%s> not found in temporal database") % (id))
+            core.fatal(_("Dataset <%s> not found in temporal database") % (st.get_id()))
         st.select(dbif)
 
     if sst.is_in_db(dbif) == False:
@@ -868,6 +868,9 @@
 
     mapset = core.gisenv()["MAPSET"]
     id = name + "@" + mapset
+    
+    print id
+    print overwrite
 
     sp = dataset_factory(type, id)
 

Added: grass/trunk/temporal/t.rast.mapcalc/test.t.rast.mapcalc.operators.sh
===================================================================
--- grass/trunk/temporal/t.rast.mapcalc/test.t.rast.mapcalc.operators.sh	                        (rev 0)
+++ grass/trunk/temporal/t.rast.mapcalc/test.t.rast.mapcalc.operators.sh	2013-01-30 22:01:00 UTC (rev 54821)
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Test for t.rast.mapcalc 
+
+# We need to set a specific region in the
+# @preprocess step of this test. We generate
+# raster with r.mapcalc and create several space time raster datasets
+# The region setting should work for UTM and LL test locations
+g.region s=0 n=80 w=0 e=120 b=0 t=50 res=10 res3=10 -p3
+
+r.mapcalc --o expr="prec_1 = rand(0, 550)"
+r.mapcalc --o expr="prec_2 = rand(0, 450)"
+r.mapcalc --o expr="prec_3 = rand(0, 320)"
+r.mapcalc --o expr="prec_4 = rand(0, 510)"
+r.mapcalc --o expr="prec_5 = rand(0, 300)"
+r.mapcalc --o expr="prec_6 = rand(0, 650)"
+
+t.create --o type=strds temporaltype=absolute output=precip_abs1 title="A test" descr="A test"
+t.create --o type=strds temporaltype=absolute output=precip_abs2 title="A test" descr="A test"
+t.register -i type=rast input=precip_abs1 maps=prec_1,prec_2,prec_3,prec_4,prec_5,prec_6 start="2001-01-01" increment="3 months"
+t.register --o type=rast input=precip_abs2 maps=prec_1,prec_2,prec_3,prec_4,prec_5,prec_6
+
+t.info precip_abs1
+t.info precip_abs2
+
+# The first @test
+t.rast.mapcalc --o --v -sn inputs=precip_abs1,precip_abs2 output=precip_abs3 \
+    expression="if(start_time() >= 0 && end_time() >= 0, (precip_abs1*td() + precip_abs2) / td(), null()) " base=new_prec \
+           method=equal nprocs=5
+t.info type=strds input=precip_abs3
+
+t.rast.mapcalc --o --v -sn inputs=precip_abs1,precip_abs2 output=precip_abs3 \
+    expression="if(start_year()>=0&&start_month()>=0&&start_day()>=0&&start_hour()>=0&&start_minute()>=0&&start_second()>=0, (precip_abs1*td() + precip_abs2) / td(), null()) " base=new_prec \
+           method=equal nprocs=5
+t.info type=strds input=precip_abs3
+
+t.rast.mapcalc --o --v -sn inputs=precip_abs1,precip_abs2 output=precip_abs3 \
+    expression="if(end_year()>=0&&end_month()>=0&&end_day()>=0&&end_hour()>=0&&end_minute()>=0&&end_second()>=0, (precip_abs1*td() + precip_abs2) / td(), null()) " base=new_prec \
+           method=equal nprocs=5
+t.info type=strds input=precip_abs3
+
+# The first @test
+t.rast.mapcalc --o --v -sn inputs=precip_abs1,precip_abs2 output=precip_abs3 \
+    expression="if(start_doy() >= 0 && start_dow() >= 0, (precip_abs1*td() + precip_abs2) / td(), null()) " base=new_prec \
+           method=equal nprocs=5
+t.info type=strds input=precip_abs3
+
+# The first @test
+t.rast.mapcalc --o --v -sn inputs=precip_abs1,precip_abs2 output=precip_abs3 \
+    expression="if(end_doy() >= 0 && end_dow() >= 0, (precip_abs1*td() + precip_abs2) / td(), null()) " base=new_prec \
+           method=equal nprocs=5
+t.info type=strds input=precip_abs3
+
+
+# @postprocess
+t.unregister type=rast maps=prec_1,prec_2,prec_3,prec_4,prec_5,prec_6
+t.unregister type=rast maps=new_prec_1,new_prec_2,new_prec_3,new_prec_4,new_prec_5,new_prec_6
+t.remove type=strds input=precip_abs1,precip_abs2,precip_abs3


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



More information about the grass-commit mailing list