-
-
Notifications
You must be signed in to change notification settings - Fork 307
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
r.surf.random: double min max for DCELL and r.mapcalc-style random nu…
…mbers The original code did not allow for floating point numbers as min and max parameters. The decimal part, if provided, was ignored without any warning. Now the code accepts doubles for DCELL output and ints for CELL output. Numbers not fully parseable as ints are now rejected by an explicit check. (The min and max values travel through the code as doubles in both cases.) With the original implementation, the max was could have been exceeded for CELL maps due to the equation used. On the other hand, the min might not have been reached with the similar probability as max could have been exceeded for ranges which contained zero. For example, in 7.6.1 using 10,000,0000 cells and -i (CELL output), parameters min=2 max=15 produce histogram (r.report u=p,c) with bins 2-15 approximatelly 7.14-15% and bin 16 with 2-4 cells. Same setup with min=-2 max=13 produces similar bin 14 with 0-5 cells, bin -2 is 0 or 1 cell, bins -1,1-15 6.25% and bin 0 12.50%. Now using the method r.mapcalc is using for rand() implemented in f_rand() in xrand.c which does not suffer from the same issues. For consistency, using the same implementation also for DCELL, so now both CELL and DCELL options are now using functions from gis.h: G_mrand48() and G_drand48(). Cconsequently, the gmath.h dependency was removed (header file includes and in the Makefile) together with unused math.h. Additionally to enforcing the int, a parameter check also enforces that min <= max since min > max seems like a input error. (This is different from r.mapcalc which flips the values, but there we assume less control over the input and it is too late to report a message, so it is appropriate and more practical to be more permissive.) min == max is allowed and not treated in a special way. Raster history is now being written as well as a map title which contains the range with interval written differently for CELL and DCELL as the CELL contains max while DCELL does not (based on [0,1) from G_drand48()). Test is provided for the min-max comparison and int-double check. A larger test provided for the generated values as well, although even with a larger number of cells the desired result might not achieved. A fixed GRASS_RANDOM_SEED is provided for stability (but it may not be the one making a future problem to show, although it does for 7.6.2). Also the exceeded max is much easier to catch than the not reached min, but both range and closeness are checked for both CELL and DCELL.
- Loading branch information
1 parent
368bb8b
commit cf78e56
Showing
5 changed files
with
230 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
/* randsurf.c */ | ||
int randsurf(char *, int, int, int); | ||
int randsurf(char *, double, double, int); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#!/usr/bin/env python3 | ||
|
||
""" | ||
MODULE: Test of r.surf.random | ||
AUTHOR(S): Vaclav Petras <wenzeslaus gmail com> | ||
PURPOSE: Test of min and max paramters | ||
COPYRIGHT: (C) 2020 by Vaclav Petras and the GRASS Development Team | ||
This program is free software under the GNU General Public | ||
License (>=v2). Read the file COPYING that comes with GRASS | ||
for details. | ||
""" | ||
|
||
import os | ||
|
||
import grass.script as gs | ||
|
||
from grass.gunittest.case import TestCase | ||
from grass.gunittest.main import test | ||
|
||
|
||
def get_raster_min_max(raster_map): | ||
info = gs.raster_info(raster_map) | ||
return info["min"], info["max"] | ||
|
||
|
||
class MinMaxTestCase(TestCase): | ||
"""Test min and max of r.surf.random module""" | ||
|
||
# Raster map name be used as output | ||
output = "random_result" | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
"""Ensures expected computational region""" | ||
os.environ["GRASS_RANDOM_SEED"] = "42" | ||
# modfying region just for this script | ||
cls.use_temp_region() | ||
# Only 100,000,000 seem to resonably (not 100%) ensure that all values | ||
# are generated, so exceeding of ranges actually shows up. | ||
cls.runModule("g.region", rows=10000, cols=10000) | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
"""Remove the temporary region""" | ||
cls.del_temp_region() | ||
|
||
def tearDown(self): | ||
"""Remove the output created from the module""" | ||
self.runModule("g.remove", flags="f", type="raster", name=[self.output]) | ||
|
||
def test_min_max_double(self): | ||
"""Check to see if double output has the expected range""" | ||
min_value = -3.3 | ||
max_value = 5.8 | ||
# arbitrary, but with more cells, we expect higher precision | ||
precision = 0.00001 | ||
self.assertModule( | ||
"r.surf.random", min=min_value, max=max_value, output=self.output, | ||
) | ||
self.assertRasterExists(self.output, msg="Output was not created") | ||
self.assertRasterMinMax( | ||
map=self.output, | ||
refmin=min_value, | ||
refmax=max_value, | ||
msg="Output exceeds the min and max values from parameters", | ||
) | ||
self.assertRasterFitsInfo( | ||
raster=self.output, | ||
reference=dict(min=min_value, max=max_value), | ||
precision=precision, | ||
msg="Output min and max too far from parameters", | ||
) | ||
|
||
def test_min_max_int(self): | ||
"""Check to see if integer output has the expected range""" | ||
# GRASS_RANDOM_SEED=42 r.surf.random output=test min=-2 max=13 -i | ||
# in 7.6.2 causes all no 2 bin and extra 14 bin (also doubles 0). | ||
min_value = -2 | ||
max_value = 13 | ||
precision = 0 | ||
self.assertModule( | ||
"r.surf.random", min=min_value, max=max_value, output=self.output, flags="i" | ||
) | ||
self.assertRasterExists(self.output, msg="Output was not created") | ||
self.assertRasterMinMax( | ||
map=self.output, | ||
refmin=min_value, | ||
refmax=max_value, | ||
msg="Output exceeds the min and max values from parameters", | ||
) | ||
self.assertRasterFitsInfo( | ||
raster=self.output, | ||
reference=dict(min=min_value, max=max_value), | ||
precision=precision, | ||
msg="Output min and max too far from parameters", | ||
) | ||
|
||
def test_double_params_with_int(self): | ||
"""Check if doubles instead of ints are refused""" | ||
min_value = -3.3 | ||
max_value = 5.8 | ||
self.assertModuleFail( | ||
"r.surf.random", min=min_value, max=max_value, output=self.output, flags="i" | ||
) | ||
|
||
def test_min_greater_than_max(self): | ||
"""Check if minimum greater than maximum is refused""" | ||
min_value = 10 | ||
max_value = 5.8 | ||
self.assertModuleFail( | ||
"r.surf.random", min=min_value, max=max_value, output=self.output | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
test() |