1from grass.gunittest.case import TestCase
2from grass.gunittest.main import test
3from grass.gunittest.gmodules import call_module
4
5SMALL_MAP = """\
6north:   15
7south:   10
8east:    25
9west:    20
10rows:    5
11cols:    5
12
13100.0 150.0 150.0 100.0 100.0
14100.0 150.0 150.0 100.0 100.0
15100.0 150.0 150.0 150.0 150.0
16100.0 150.0 150.0 100.0 100.0
17100.0 150.0 150.0 100.0 100.0
18"""
19
20class TestSlopeAspect(TestCase):
21
22    slope = 'limits_slope'
23    aspect = 'limits_aspect'
24
25    def setUp(self):
26        self.use_temp_region()
27        call_module('g.region', raster='elevation')
28
29    def tearDown(self):
30        self.del_temp_region()
31        call_module('g.remove', flags='f', type_='raster',
32                    name=[self.slope, self.aspect])
33
34    def test_limits(self):
35        self.assertModule('r.slope.aspect', elevation='elevation',
36                          slope=self.slope, aspect=self.aspect)
37        self.assertRasterMinMax(map=self.slope, refmin=0, refmax=90,
38                                msg="Slope in degrees must be between 0 and 90")
39        self.assertRasterMinMax(map=self.aspect, refmin=0, refmax=360,
40                                msg="Aspect in degrees must be between 0 and 360")
41
42    def test_limits_precent(self):
43        """Assumes NC elevation and allows slope up to 100% (45deg)"""
44        self.assertModule('r.slope.aspect', elevation='elevation',
45                          slope=self.slope, aspect=self.aspect, format='percent')
46        self.assertRasterMinMax(map=self.slope, refmin=0, refmax=100,
47                                msg="Slope in percent must be between 0 and 100")
48        self.assertRasterMinMax(map=self.aspect, refmin=0, refmax=360,
49                                msg="Aspect in degrees must be between 0 and 360")
50
51
52class TestSlopeAspectAgainstReference(TestCase):
53    """
54
55    Data created using::
56
57        g.region n=20 s=10 e=25 w=15 res=1
58        r.surf.fractal output=fractal_surf
59        r.out.ascii input=fractal_surf output=data/fractal_surf.ascii
60        gdaldem slope .../fractal_surf.ascii .../gdal_slope.grd -of GSAG
61        gdaldem aspect .../fractal_surf.ascii .../gdal_aspect.grd -of GSAG -trigonometric
62
63    GDAL version 1.11.0 was used. Note: GDAL-slope/aspect implementation is originally based on
64    GRASS GIS 4.1.
65    """
66
67    # precision for comparisons
68    precision = 0.0001
69    ref_aspect = 'reference_aspect'
70    aspect = 'fractal_aspect'
71    ref_slope = 'reference_slope'
72    slope = 'fractal_slope'
73
74    @classmethod
75    def setUpClass(cls):
76        cls.use_temp_region()
77        call_module('g.region', n=20, s=10, e=25, w=15, res=1)
78        cls.elevation = 'fractal_surf'
79        cls.runModule('r.in.ascii', input='data/fractal_surf.ascii',
80                      output=cls.elevation)
81
82    @classmethod
83    def tearDownClass(cls):
84        cls.del_temp_region()
85        cls.runModule('g.remove', flags='f', type='raster',
86                      name=[cls.elevation, cls.slope, cls.aspect, cls.ref_aspect, cls.ref_slope])
87
88    def test_slope(self):
89        # TODO: using gdal instead of ascii because of cannot seek error
90        self.runModule('r.in.gdal', flags='o',
91                       input='data/gdal_slope.grd', output=self.ref_slope)
92        self.assertModule('r.slope.aspect', elevation=self.elevation,
93                          slope=self.slope)
94        # check we have expected values
95        self.assertRasterMinMax(map=self.slope, refmin=0, refmax=90,
96                                msg="Slope in degrees must be between 0 and 90")
97        # check against reference data
98        self.assertRastersNoDifference(actual=self.slope, reference=self.ref_slope,
99                                       precision=self.precision)
100
101    def test_aspect(self):
102        # TODO: using gdal instead of ascii because of cannot seek error
103        self.runModule('r.in.gdal', flags='o',
104                       input='data/gdal_aspect.grd', output=self.ref_aspect)
105        self.assertModule('r.slope.aspect', elevation=self.elevation,
106                          aspect=self.aspect)
107        # check we have expected values
108        self.assertRasterMinMax(map=self.aspect, refmin=0, refmax=360,
109                                msg="Aspect in degrees must be between 0 and 360")
110        # check against reference data
111        self.assertRastersNoDifference(actual=self.aspect, reference=self.ref_aspect,
112                                       precision=self.precision)
113
114
115class TestSlopeAspectAgainstItself(TestCase):
116
117    precision = 0.0000001
118    elevation = 'elevation'
119    t_aspect = 'sa_together_aspect'
120    t_slope = 'sa_together_slope'
121    s_aspect = 'sa_separately_aspect'
122    s_slope = 'sa_separately_slope'
123
124    @classmethod
125    def setUpClass(cls):
126        cls.use_temp_region()
127        call_module('g.region', raster='elevation')
128
129    @classmethod
130    def tearDownClass(cls):
131        cls.del_temp_region()
132        call_module('g.remove', flags='f', type_='raster',
133                    name=[cls.t_aspect, cls.t_slope, cls.s_slope, cls.s_aspect])
134
135    def test_slope_aspect_together(self):
136        """Slope and aspect computed separately and together should be the same
137        """
138        self.assertModule('r.slope.aspect', elevation=self.elevation,
139                          aspect=self.s_aspect)
140        self.assertModule('r.slope.aspect', elevation=self.elevation,
141                          slope=self.s_slope)
142        self.assertModule('r.slope.aspect', elevation=self.elevation,
143                          slope=self.t_slope, aspect=self.t_aspect)
144        self.assertRastersNoDifference(actual=self.t_aspect, reference=self.s_aspect,
145                                       precision=self.precision)
146        self.assertRastersNoDifference(actual=self.t_slope, reference=self.s_slope,
147                                       precision=self.precision)
148
149
150# TODO: implement this class
151class TestExtremes(TestCase):
152
153    slope = 'small_slope'
154    aspect = 'small_aspect'
155    elevation = 'small_elevation'
156
157    def setUp(self):
158        self.use_temp_region()
159
160    def tearDown(self):
161        self.del_temp_region()
162        call_module('g.remove', flags='f', type_='raster',
163                    name=[self.slope, self.aspect, self.elevation])
164
165    def test_small(self):
166        self.runModule('r.in.ascii', input='-', output=self.elevation,
167                       stdin_=SMALL_MAP)
168        call_module('g.region', raster=self.elevation)
169        self.assertModule('r.slope.aspect', elevation=self.elevation,
170                          slope=self.slope, aspect=self.aspect)
171        self.assertRasterMinMax(map=self.slope, refmin=0, refmax=90,
172                                msg="Slope in degrees must be between 0 and 90")
173        self.assertRasterMinMax(map=self.aspect, refmin=0, refmax=360,
174                                msg="Aspect in degrees must be between 0 and 360")
175
176
177if __name__ == '__main__':
178    test()
179