[GRASS-SVN] r61475 - in grass/branches/releasebranch_7_0: gui/wxpython/modules lib/init lib/python/script raster/r.mapcalc temporal/t.rast.neighbors

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Jul 31 05:08:48 PDT 2014


Author: neteler
Date: 2014-07-31 05:08:48 -0700 (Thu, 31 Jul 2014)
New Revision: 61475

Modified:
   grass/branches/releasebranch_7_0/gui/wxpython/modules/mcalc_builder.py
   grass/branches/releasebranch_7_0/lib/init/variables.html
   grass/branches/releasebranch_7_0/lib/python/script/raster.py
   grass/branches/releasebranch_7_0/raster/r.mapcalc/evaluate.c
   grass/branches/releasebranch_7_0/raster/r.mapcalc/globals.h
   grass/branches/releasebranch_7_0/raster/r.mapcalc/main.c
   grass/branches/releasebranch_7_0/raster/r.mapcalc/map.c
   grass/branches/releasebranch_7_0/raster/r.mapcalc/r.mapcalc.html
   grass/branches/releasebranch_7_0/raster/r.mapcalc/r3.mapcalc.html
   grass/branches/releasebranch_7_0/raster/r.mapcalc/xrand.c
   grass/branches/releasebranch_7_0/temporal/t.rast.neighbors/t.rast.neighbors.html
Log:
r.mapcalc: Replace GRASS_RND_SEED with seed= option and -s flag, Use lib/gis PRNG, Store seed in history (r61353); wxGUI/mapcalc: seed handling added to the interface (r61354); GRASS_RND_SEED replaced by seed= (r61358); Add seed= parameter to grass.script.mapcalc() (r61388); python: Add env= parameter to mapcalc, mapcalc_start, raster_what (r61428)

Modified: grass/branches/releasebranch_7_0/gui/wxpython/modules/mcalc_builder.py
===================================================================
--- grass/branches/releasebranch_7_0/gui/wxpython/modules/mcalc_builder.py	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/gui/wxpython/modules/mcalc_builder.py	2014-07-31 12:08:48 UTC (rev 61475)
@@ -28,6 +28,7 @@
 from core.utils import _
 from gui_core.gselect import Select
 from gui_core.forms   import GUI
+from gui_core.widgets import IntegerValidator
 from core.settings    import UserSettings
 
 class MapCalcFrame(wx.Frame):
@@ -230,7 +231,18 @@
         self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
                                      label=_("Allow output files to overwrite existing files"))
         self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
+
+        self.randomSeed = wx.CheckBox(parent=self.panel,
+                                      label=_("Generate random seed for rand()"))
+        self.randomSeedStaticText = wx.StaticText(parent=self.panel, label=_("Seed:"))
+        self.randomSeedText = wx.TextCtrl(parent=self.panel, size=(100, -1),
+                                          validator=IntegerValidator())
+        self.randomSeedText.SetToolTipString(_("Integer seed for rand() function"))
+        self.randomSeed.SetValue(True)
+        self.randomSeedStaticText.Disable()
+        self.randomSeedText.Disable()
         
+
         self.addbox = wx.CheckBox(parent=self.panel,
                                   label=_('Add created raster map into layer tree'), style = wx.NO_BORDER)
         self.addbox.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
@@ -258,6 +270,9 @@
         self.newmaptxt.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
         self.text_mcalc.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
         self.overwrite.Bind(wx.EVT_CHECKBOX, self.OnUpdateStatusBar)
+        self.randomSeed.Bind(wx.EVT_CHECKBOX, self.OnUpdateStatusBar)
+        self.randomSeed.Bind(wx.EVT_CHECKBOX, self.OnSeedFlag)
+        self.randomSeedText.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
 
         self._layout()
 
@@ -379,7 +394,17 @@
                   border = 5)
         sizer.Add(item = buttonSizer4, proportion = 0,
                   flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
-        
+
+        randomSizer = wx.BoxSizer(wx.HORIZONTAL)
+        randomSizer.Add(item=self.randomSeed, proportion=0,
+                        flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border=20)
+        randomSizer.Add(item=self.randomSeedStaticText, proportion=0,
+                        flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border=5)
+        randomSizer.Add(item=self.randomSeedText, proportion=0)
+        sizer.Add(item=randomSizer, proportion=0,
+                  flag=wx.LEFT | wx.RIGHT,
+                  border=5)
+
         sizer.Add(item = self.overwrite, proportion = 0,
                   flag = wx.LEFT | wx.RIGHT,
                   border = 5)
@@ -458,6 +483,13 @@
         self.SetStatusText(command)
         event.Skip()
 
+    def OnSeedFlag(self, event):
+        checked = self.randomSeed.IsChecked()
+        self.randomSeedText.Enable(not checked)
+        self.randomSeedStaticText.Enable(not checked)
+
+        event.Skip()
+
     def _getCommand(self):
         """Returns entire command as string."""
         expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
@@ -467,10 +499,17 @@
         overwrite = ''
         if self.overwrite.IsChecked():
             overwrite = ' --overwrite'
-        return '{cmd} "{new} = {expr}"{overwrite}'.format(cmd=cmd, expr=expr,
-                                                          new=self.newmaptxt.GetValue(),
-                                                          overwrite=overwrite)
+        seed_flag = seed = ''
+        if re.search(pattern="rand *\(.+\)", string=expr):
+            if self.randomSeed.IsChecked():
+                seed_flag = ' -s'
+            else:
+                seed = " seed={val}".format(val=self.randomSeedText.GetValue().strip())
 
+        return ('{cmd} "{new} = {expr}"{seed}{seed_flag}{overwrite}'
+                .format(cmd=cmd, expr=expr, new=self.newmaptxt.GetValue(),
+                        seed_flag=seed_flag, seed=seed, overwrite=overwrite))
+
     def _addSomething(self, what):
         """!Inserts operators, map names, and functions into text area
         """
@@ -520,11 +559,23 @@
                    message = _("You must enter an expression "
                                "to create a new raster map."))
             return
-        
+
+        seed_flag = seed = None
+        if re.search(pattern="rand *\(.+\)", string=expr):
+            if self.randomSeed.IsChecked():
+                seed_flag = '-s'
+            else:
+                seed = self.randomSeedText.GetValue().strip()
         if self.log:
-            cmd = [self.cmd, str('expression=%s = %s' % (name, expr))]
+            cmd = [self.cmd]
+            if seed_flag:
+                cmd.append('-s')
+            if seed:
+                cmd.append("seed={val}".format(val=seed))
             if self.overwrite.IsChecked():
                 cmd.append('--overwrite')
+            cmd.append(str('expression=%s = %s' % (name, expr)))
+
             self.log.RunCmd(cmd, onDone = self.OnDone)
             self.parent.Raise()
         else:
@@ -532,10 +583,16 @@
                 overwrite = True
             else:
                 overwrite = False
+            params = dict(expression="%s=%s" % (name, expr),
+                          overwrite=overwrite)
+            if seed_flag:
+                params['flags'] = 's'
+            if seed:
+                params['seed'] = seed
+
             RunCommand(self.cmd,
-                       expression = "%s=%s" % (name, expr),
-                       overwrite = overwrite)
-        
+                       **params)
+
     def OnDone(self, cmd, returncode):
         """!Add create map to the layer tree
 

Modified: grass/branches/releasebranch_7_0/lib/init/variables.html
===================================================================
--- grass/branches/releasebranch_7_0/lib/init/variables.html	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/lib/init/variables.html	2014-07-31 12:08:48 UTC (rev 61475)
@@ -201,11 +201,6 @@
   <dd>[used during install process for generating man pages]<br>
     set Perl with path.</dd>
   
-  <dt>GRASS_RND_SEED</dt>
-  <dd>set random seed
-    for <em><a href="r.mapcalc.html">r.mapcalc</a></em> rand()
-    function.</dd>
-
   <dt>GRASS_SKIP_MAPSET_OWNER_CHECK</dt>
   <dd>By default it is not possible to work with MAPSETs that are
     not owned by current user. Setting this variable to any non-empty value

Modified: grass/branches/releasebranch_7_0/lib/python/script/raster.py
===================================================================
--- grass/branches/releasebranch_7_0/lib/python/script/raster.py	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/lib/python/script/raster.py	2014-07-31 12:08:48 UTC (rev 61475)
@@ -25,6 +25,7 @@
 import os
 import string
 import types
+import time
 
 from core import *
 
@@ -86,26 +87,37 @@
 
 # interface to r.mapcalc
 
-def mapcalc(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
+def mapcalc(exp, quiet = False, verbose = False, overwrite = False,
+            seed = None, env = None, **kwargs):
     """!Interface to r.mapcalc.
 
     @param exp expression
     @param quiet True to run quietly (<tt>--q</tt>)
     @param verbose True to run verbosely (<tt>--v</tt>)
     @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+    @param seed an integer used to seed the random-number generator for the rand() function,
+    or 'auto' to generate a random seed
+    @param env dictionary of environment variables for child process
     @param kwargs
     """
+
+    if seed == 'auto':
+        seed = hash((os.getpid(), time.time())) % (2**32)
+
     t = string.Template(exp)
     e = t.substitute(**kwargs)
 
     if write_command('r.mapcalc', file = '-', stdin = e,
+                     env = env,
+                     seed = seed,
                      quiet = quiet,
                      verbose = verbose,
                      overwrite = overwrite) != 0:
         fatal(_("An error occurred while running r.mapcalc"))
 
 
-def mapcalc_start(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
+def mapcalc_start(exp, quiet = False, verbose = False, overwrite = False,
+                  seed = None, env = None, **kwargs):
     """!Interface to r.mapcalc, doesn't wait for it to finish, returns Popen object.
 
     \code
@@ -124,14 +136,23 @@
     @param quiet True to run quietly (<tt>--q</tt>)
     @param verbose True to run verbosely (<tt>--v</tt>)
     @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+    @param seed an integer used to seed the random-number generator for the rand() function,
+    or 'auto' to generate a random seed
+    @param env dictionary of environment variables for child process
     @param kwargs
     
     @return Popen object
     """
+
+    if seed == 'auto':
+        seed = hash((os.getpid(), time.time())) % (2**32)
+
     t = string.Template(exp)
     e = t.substitute(**kwargs)
 
     p = feed_command('r.mapcalc', file = '-',
+                     env = env,
+                     seed = seed,
                      quiet = quiet,
                      verbose = verbose,
                      overwrite = overwrite)
@@ -140,7 +161,7 @@
     return p
 
 # interface to r.what
-def raster_what(map, coord):
+def raster_what(map, coord, env = None):
     """!TODO"""
     if type(map) in (types.StringType, types.UnicodeType):
         map_list = [map]
@@ -158,14 +179,13 @@
     # separator '|' not included in command
     # because | is causing problems on Windows
     # change separator?
-    cmdParams = dict(quiet = True,
-                     flags = 'rf',
-                     map = ','.join(map_list),
-                     coordinates = ','.join(coord_list),
-                     null = _("No data"))
-    
     ret = read_command('r.what',
-                       **cmdParams)
+                       flags = 'rf',
+                       map = ','.join(map_list),
+                       coordinates = ','.join(coord_list),
+                       null = _("No data"),
+                       quiet = True,
+                       env = env)
     data = list()
     if not ret:
         return data

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/evaluate.c
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/evaluate.c	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/evaluate.c	2014-07-31 12:08:48 UTC (rev 61475)
@@ -254,26 +254,6 @@
     }
 }
 
-static void setup_rand(void)
-{
-    /* Read PRNG seed from environment variable if available */
-    /* GRASS_RND_SEED */
-    const char *random_seed = getenv("GRASS_RND_SEED");
-    long seed_value;
-
-    if (!random_seed)
-	return;
-
-    seed_value = atol(random_seed);
-    G_debug(3, "Read random seed from environment: %ld", seed_value);
-
-#if defined(HAVE_DRAND48)
-    srand48(seed_value);
-#else
-    srand((unsigned int)seed_value);
-#endif
-}
-
 void execute(expr_list * ee)
 {
     int verbose = isatty(2);
@@ -281,7 +261,6 @@
     int count, n;
 
     setup_region();
-    setup_rand();
 
     exprs = ee;
     G_add_error_handler(error_handler, NULL);

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/globals.h
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/globals.h	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/globals.h	2014-07-31 12:08:48 UTC (rev 61475)
@@ -6,6 +6,8 @@
 extern volatile int floating_point_exception_occurred;
 extern int overflow_occurred;
 extern int overwrite_flag;
+extern long seed_value;
+extern long seeded;
 
 extern int current_depth, current_row;
 extern int depths, rows, columns;

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/main.c
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/main.c	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/main.c	2014-07-31 12:08:48 UTC (rev 61475)
@@ -31,6 +31,9 @@
 volatile int floating_point_exception;
 volatile int floating_point_exception_occurred;
 
+long seed_value;
+long seeded;
+
 /****************************************************************************/
 
 static expr_list *result;
@@ -102,7 +105,8 @@
 int main(int argc, char **argv)
 {
     struct GModule *module;
-    struct Option *expr, *file;
+    struct Option *expr, *file, *seed;
+    struct Flag *random;
     int all_ok;
 
     G_gisinit(argv[0]);
@@ -126,6 +130,16 @@
     file->description = _("File containing expression(s) to evaluate");
     file->guisection = _("Expression");
 
+    seed = G_define_option();
+    seed->key = "seed";
+    seed->type = TYPE_INTEGER;
+    seed->required = NO;
+    seed->description = _("Seed for rand() function");
+
+    random = G_define_flag();
+    random->key = 's';
+    random->description = _("Generate random seed (result is non-deterministic)");
+
     if (argc == 1)
     {
 	char **p = G_malloc(3 * sizeof(char *));
@@ -144,6 +158,10 @@
     if (expr->answer && file->answer)
 	G_fatal_error(_("file= and expression= are mutually exclusive"));
 
+    if (seed->answer && random->answer)
+	G_fatal_error(_("%s= and -%c are mutually exclusive"),
+		      seed->key, random->key);
+
     if (expr->answer)
 	result = parse_string(expr->answer);
     else if (file->answer)
@@ -154,6 +172,19 @@
     if (!result)
 	G_fatal_error(_("parse error"));
 
+    if (seed->answer) {
+	seed_value = atol(seed->answer);
+	G_srand48(seed_value);
+	seeded = 1;
+	G_debug(3, "Read random seed from seed=: %ld", seed_value);
+    }
+
+    if (random->answer) {
+	seed_value = G_srand48_auto();
+	seeded = 1;
+	G_debug(3, "Generated random seed (-s): %ld", seed_value);
+    }
+
     pre_exec();
     execute(result);
     post_exec();

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/map.c
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/map.c	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/map.c	2014-07-31 12:08:48 UTC (rev 61475)
@@ -740,6 +740,12 @@
 	len -= n;
     }
 
+    if (seeded) {
+	char buf[RECORD_LEN];
+	sprintf(buf, "random seed = %ld", seed_value);
+	Rast_append_history(&hist, buf);
+    }
+
     Rast_write_history(dst, &hist);
 
     G_free(expr);

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/r.mapcalc.html
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/r.mapcalc.html	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/r.mapcalc.html	2014-07-31 12:08:48 UTC (rev 61475)
@@ -609,8 +609,20 @@
 (map) must be changed.
 
 <h3>Random number generator initialization</h3>
-<p>The environment variable GRASS_RND_SEED is read to initialize the
-random number generator.
+<p>The pseudo-random number generator used by the rand() function can
+be initialised to a specific value using the <em>seed</em> option. 
+This can be used to replicate a previous calculation.
+<p>Alternatively, it can be initialised from the system time and the
+PID using the <em>-r</em> flag. This should result in a different seed
+being used each time.
+<p>In either case, the seed will be written to the map's history, and
+can be seen using <em>r.info</em>.
+<p>If you want other people to be able to verify your results, it's
+preferable to use the <em>seed</em> option to supply a seed which is
+either specified in the script or generated from a determenistic process
+such as a pseudo-random number generator given an explicit seed.
+<p>Note that the rand() function will generate a fatal error if neither
+the <em>seed</em> option nor the <em>-s</em> flag are given.
 
 <h2>EXAMPLES</h2>
 To compute the average of two raster map layers

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/r3.mapcalc.html
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/r3.mapcalc.html	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/r3.mapcalc.html	2014-07-31 12:08:48 UTC (rev 61475)
@@ -470,8 +470,20 @@
 See <em><a href="r.mask.html">r.mask</a></em> for details.
 
 <h3>Random number generator initialization</h3>
-<p>The environment variable GRASS_RND_SEED is read to initialize the
-random number generator.
+<p>The pseudo-random number generator used by the rand() function can
+be initialised to a specific value using the <em>seed</em> option. 
+This can be used to replicate a previous calculation.
+<p>Alternatively, it can be initialised from the system time and the
+PID using the <em>-r</em> flag. This should result in a different seed
+being used each time.
+<p>In either case, the seed will be written to the map's history, and
+can be seen using <em>r.info</em>.
+<p>If you want other people to be able to verify your results, it's
+preferable to use the <em>seed</em> option to supply a seed which is
+either specified in the script or generated from a determenistic process
+such as a pseudo-random number generator given an explicit seed.
+<p>Note that the rand() function will generate a fatal error if neither
+the <em>seed</em> option nor the <em>-s</em> flag are given.
 
 <h2>EXAMPLES</h2>
 To compute the average of two 3D grids

Modified: grass/branches/releasebranch_7_0/raster/r.mapcalc/xrand.c
===================================================================
--- grass/branches/releasebranch_7_0/raster/r.mapcalc/xrand.c	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/raster/r.mapcalc/xrand.c	2014-07-31 12:08:48 UTC (rev 61475)
@@ -12,11 +12,6 @@
 rand(lo,hi) random values between a and b
 ****************************************************************/
 
-#if !defined(HAVE_DRAND48)
-#define drand48() ((double)rand()/((double)RAND_MAX + 1))
-#define mrand48() ((long)rand())
-#endif
-
 int f_rand(int argc, const int *argt, void **args)
 {
     int i;
@@ -34,7 +29,7 @@
 	    CELL *arg2 = args[2];
 
 	    for (i = 0; i < columns; i++) {
-		unsigned long x = (unsigned long)mrand48();
+		unsigned long x = (unsigned long)G_mrand48();
 		int lo = arg1[i];
 		int hi = arg2[i];
 
@@ -55,7 +50,7 @@
 	    FCELL *arg2 = args[2];
 
 	    for (i = 0; i < columns; i++) {
-		double x = drand48();
+		double x = G_drand48();
 		FCELL lo = arg1[i];
 		FCELL hi = arg2[i];
 
@@ -76,7 +71,7 @@
 	    DCELL *arg2 = args[2];
 
 	    for (i = 0; i < columns; i++) {
-		double x = drand48();
+		double x = G_drand48();
 		DCELL lo = arg1[i];
 		DCELL hi = arg2[i];
 

Modified: grass/branches/releasebranch_7_0/temporal/t.rast.neighbors/t.rast.neighbors.html
===================================================================
--- grass/branches/releasebranch_7_0/temporal/t.rast.neighbors/t.rast.neighbors.html	2014-07-31 11:48:14 UTC (rev 61474)
+++ grass/branches/releasebranch_7_0/temporal/t.rast.neighbors/t.rast.neighbors.html	2014-07-31 12:08:48 UTC (rev 61475)
@@ -34,8 +34,7 @@
 
 count=1
 for map in ${MAPS} ; do
-    export GRASS_RND_SEED=${count}
-    r.mapcalc --o expr="${map} = rand(0, 550)" 
+    r.mapcalc --o expr="${map} = rand(0, 550)" seed=${count}
     echo ${map} >> map_list.txt 
     count=$((count+1))
 done



More information about the grass-commit mailing list