yirgacheffe 1.3.3__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {yirgacheffe-1.3.3/yirgacheffe.egg-info → yirgacheffe-1.3.4}/PKG-INFO +1 -1
  2. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/pyproject.toml +1 -1
  3. yirgacheffe-1.3.4/tests/test_area.py +21 -0
  4. yirgacheffe-1.3.4/tests/test_auto_windowing.py +284 -0
  5. yirgacheffe-1.3.4/tests/test_constants.py +32 -0
  6. yirgacheffe-1.3.4/tests/test_datatypes.py +67 -0
  7. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_group.py +4 -4
  8. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_h3layer.py +9 -7
  9. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_intersection.py +1 -1
  10. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_multiband.py +2 -2
  11. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_operators.py +2 -3
  12. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_optimisation.py +2 -2
  13. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_parallel_operators.py +3 -3
  14. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_pickle.py +3 -2
  15. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_raster.py +3 -3
  16. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_rescaling.py +1 -1
  17. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_save_with_window.py +1 -1
  18. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_sum_with_window.py +1 -1
  19. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_uniform_area_layer.py +1 -1
  20. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_union.py +1 -1
  21. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_vectors.py +14 -4
  22. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/operators.py +22 -3
  23. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4/yirgacheffe.egg-info}/PKG-INFO +1 -1
  24. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe.egg-info/SOURCES.txt +1 -0
  25. yirgacheffe-1.3.3/tests/test_area.py +0 -21
  26. yirgacheffe-1.3.3/tests/test_auto_windowing.py +0 -284
  27. yirgacheffe-1.3.3/tests/test_datatypes.py +0 -67
  28. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/LICENSE +0 -0
  29. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/MANIFEST.in +0 -0
  30. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/README.md +0 -0
  31. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/setup.cfg +0 -0
  32. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_base.py +0 -0
  33. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_rounding.py +0 -0
  34. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/tests/test_window.py +0 -0
  35. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/__init__.py +0 -0
  36. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/backends/__init__.py +0 -0
  37. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/backends/enumeration.py +0 -0
  38. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/backends/mlx.py +0 -0
  39. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/backends/numpy.py +0 -0
  40. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/constants.py +0 -0
  41. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/h3layer.py +0 -0
  42. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/__init__.py +0 -0
  43. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/area.py +0 -0
  44. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/base.py +0 -0
  45. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/constant.py +0 -0
  46. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/group.py +0 -0
  47. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/h3layer.py +0 -0
  48. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/rasters.py +0 -0
  49. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/rescaled.py +0 -0
  50. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/layers/vectors.py +0 -0
  51. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/rounding.py +0 -0
  52. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe/window.py +0 -0
  53. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe.egg-info/dependency_links.txt +0 -0
  54. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe.egg-info/entry_points.txt +0 -0
  55. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe.egg-info/requires.txt +0 -0
  56. {yirgacheffe-1.3.3 → yirgacheffe-1.3.4}/yirgacheffe.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yirgacheffe
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: Abstraction of gdal datasets for doing basic math operations
5
5
  Author-email: Michael Dales <mwd24@cam.ac.uk>
6
6
  License-Expression: ISC
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "yirgacheffe"
9
- version = "1.3.3"
9
+ version = "1.3.4"
10
10
  description = "Abstraction of gdal datasets for doing basic math operations"
11
11
  readme = "README.md"
12
12
  authors = [{ name = "Michael Dales", email = "mwd24@cam.ac.uk" }]
@@ -0,0 +1,21 @@
1
+ import pytest
2
+
3
+ # I've no idea why pylint dislikes this particular import but accepts
4
+ # other entries in the module.
5
+ from yirgacheffe.window import Area # pylint: disable=E0401, E0611
6
+
7
+ @pytest.mark.parametrize(
8
+ "lhs,rhs,is_equal,overlaps",
9
+ [
10
+ # Obvious equality
11
+ (Area(-10.0, 10.0, 10.0, -10.0), Area(-10.0, 10.0, 10.0, -10.0), True, True),
12
+ (Area(-9.0, 9.0, 9.0, -9.0), Area(-10.0, 10.0, 10.0, -10.0), False, True), # subset
13
+ (Area(-9.0, 9.0, -1.0, 1.0), Area(1.0, -1.0, 9.0, -9.0), False, False),
14
+ (Area(-10.0, 10.0, 1.0, -10.0), Area(-1.0, 10.0, 10.0, -10.0), False, True),
15
+ ]
16
+ )
17
+ def test_area_operators(lhs: Area, rhs: Area, is_equal: bool, overlaps: bool) -> None:
18
+ assert (lhs == rhs) == is_equal
19
+ assert (lhs != rhs) == (not is_equal)
20
+ assert (lhs.overlaps(rhs)) == overlaps
21
+ assert (rhs.overlaps(lhs)) == overlaps
@@ -0,0 +1,284 @@
1
+ import os
2
+ import tempfile
3
+
4
+ import numpy as np
5
+ import pytest
6
+
7
+ import yirgacheffe
8
+ from tests.helpers import gdal_dataset_with_data, make_vectors_with_mutlile_ids
9
+ from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer
10
+ from yirgacheffe.window import Area
11
+
12
+ def test_add_windows() -> None:
13
+ data1 = np.array([[1, 2], [3, 4]])
14
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
15
+
16
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
17
+ layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
18
+
19
+ assert layer1.area != layer2.area
20
+ assert layer1.window != layer2.window
21
+
22
+ calc = layer1 + layer2
23
+
24
+ assert calc.area == layer2.area
25
+ assert calc.window == layer2.window
26
+
27
+ result = RasterLayer.empty_raster_layer_like(calc)
28
+ calc.save(result)
29
+
30
+ expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
31
+ actual = result.read_array(0, 0, 4, 4)
32
+ assert (expected == actual).all()
33
+
34
+ def test_multiply_windows() -> None:
35
+ data1 = np.array([[1, 2], [3, 4]])
36
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
37
+
38
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
39
+ layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
40
+
41
+ assert layer1.area != layer2.area
42
+ assert layer1.window != layer2.window
43
+
44
+ calc = layer1 * layer2
45
+
46
+ assert calc.area == layer1.area
47
+ assert calc.window == layer1.window
48
+
49
+ result = RasterLayer.empty_raster_layer_like(calc)
50
+ calc.save(result)
51
+
52
+ expected = np.array([[10, 40], [150, 240]])
53
+ actual = result.read_array(0, 0, 2, 2)
54
+ assert (expected == actual).all()
55
+
56
+ def test_add_windows_offset() -> None:
57
+ data1 = np.array([[1, 2], [3, 4]])
58
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
59
+
60
+ layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
61
+ layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
62
+
63
+ assert layer1.area != layer2.area
64
+ assert layer1.window != layer2.window
65
+
66
+ calc = layer1 + layer2
67
+
68
+ assert calc.area == layer2.area
69
+
70
+ result = RasterLayer.empty_raster_layer_like(calc)
71
+ calc.save(result)
72
+
73
+ expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
74
+ actual = result.read_array(0, 0, 4, 4)
75
+ assert (expected == actual).all()
76
+
77
+ def test_multiply_windows_offset() -> None:
78
+ data1 = np.array([[1, 2], [3, 4]])
79
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
80
+
81
+ layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
82
+ layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
83
+
84
+ assert layer1.area != layer2.area
85
+ assert layer1.window != layer2.window
86
+
87
+ calc = layer1 * layer2
88
+
89
+ assert calc.area == layer1.area
90
+
91
+ result = RasterLayer.empty_raster_layer_like(calc)
92
+ calc.save(result)
93
+
94
+ expected = np.array([[60, 140], [300, 440]])
95
+ actual = result.read_array(0, 0, 2, 2)
96
+ assert (expected == actual).all()
97
+
98
+ def test_add_windows_sum() -> None:
99
+ data1 = np.array([[1, 2], [3, 4]])
100
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
101
+
102
+ layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
103
+ layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
104
+
105
+ calc = layer1 + layer2
106
+ total = calc.sum()
107
+
108
+ expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
109
+ assert total == np.sum(expected)
110
+
111
+ def test_multiply_windows_sum() -> None:
112
+ data1 = np.array([[1, 2], [3, 4]])
113
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
114
+
115
+ layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
116
+ layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
117
+
118
+ calc = layer1 * layer2
119
+ total = calc.sum()
120
+
121
+ expected = np.array([[60, 140], [300, 440]])
122
+ assert total == np.sum(expected)
123
+
124
+ def test_constant_layer_result_rhs_add() -> None:
125
+ data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
126
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
127
+ const_layer = ConstantLayer(1.0)
128
+
129
+ calc = layer1 + const_layer
130
+
131
+ assert calc.area == layer1.area
132
+
133
+ result = RasterLayer.empty_raster_layer_like(calc)
134
+ calc.save(result)
135
+ actual = result.read_array(0, 0, 4, 2)
136
+
137
+ expected = 1.0 + data1
138
+
139
+ assert (expected == actual).all()
140
+
141
+ def test_constant_layer_result_lhs_add() -> None:
142
+ data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
143
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
144
+ const_layer = ConstantLayer(1.0)
145
+ result = RasterLayer.empty_raster_layer_like(layer1)
146
+
147
+ intersection = RasterLayer.find_intersection([layer1, const_layer])
148
+ const_layer.set_window_for_intersection(intersection)
149
+ layer1.set_window_for_intersection(intersection)
150
+
151
+ calc = const_layer + layer1
152
+
153
+ assert calc.area == layer1.area
154
+
155
+ result = RasterLayer.empty_raster_layer_like(calc)
156
+ calc.save(result)
157
+ actual = result.read_array(0, 0, 4, 2)
158
+
159
+ expected = 1.0 + data1
160
+
161
+ assert (expected == actual).all()
162
+
163
+ def test_constant_layer_result_rhs_multiply() -> None:
164
+ data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
165
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
166
+ const_layer = ConstantLayer(2.0)
167
+
168
+ calc = layer1 * const_layer
169
+
170
+ assert calc.area == layer1.area
171
+
172
+ result = RasterLayer.empty_raster_layer_like(calc)
173
+ calc.save(result)
174
+ actual = result.read_array(0, 0, 4, 2)
175
+
176
+ expected = data1 * 2.0
177
+
178
+ assert (expected == actual).all()
179
+
180
+ def test_constant_layer_result_lhs_multiply() -> None:
181
+ data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
182
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
183
+ const_layer = ConstantLayer(2.0)
184
+ result = RasterLayer.empty_raster_layer_like(layer1)
185
+
186
+ intersection = RasterLayer.find_intersection([layer1, const_layer])
187
+ const_layer.set_window_for_intersection(intersection)
188
+ layer1.set_window_for_intersection(intersection)
189
+
190
+ calc = const_layer * layer1
191
+
192
+ assert calc.area == layer1.area
193
+
194
+ result = RasterLayer.empty_raster_layer_like(calc)
195
+ calc.save(result)
196
+ actual = result.read_array(0, 0, 4, 2)
197
+
198
+ expected = 2.0 * data1
199
+
200
+ assert (expected == actual).all()
201
+
202
+ def test_vector_layers_add() -> None:
203
+ data1 = np.array([[1, 2], [3, 4]])
204
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 1.0, data1))
205
+
206
+ with tempfile.TemporaryDirectory() as tempdir:
207
+ path = os.path.join(tempdir, "test.gpkg")
208
+ areas = {
209
+ (Area(-10.0, 10.0, 0.0, 0.0), 42),
210
+ (Area(0.0, 0.0, 10, -10), 43)
211
+ }
212
+ make_vectors_with_mutlile_ids(areas, path)
213
+
214
+ burn_value = 2
215
+ layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
216
+ layer2_total = layer2.sum()
217
+ assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
218
+
219
+ calc = layer1 + layer2
220
+
221
+ assert calc.area == layer2.area
222
+
223
+ total = calc.sum()
224
+ assert total == layer2_total + np.sum(data1)
225
+
226
+ def test_vector_layers_multiply() -> None:
227
+ data1 = np.array([[1, 2], [3, 4]])
228
+ layer1 = RasterLayer(gdal_dataset_with_data((-1.0, 1.0), 1.0, data1))
229
+
230
+ with tempfile.TemporaryDirectory() as tempdir:
231
+ path = os.path.join(tempdir, "test.gpkg")
232
+ areas = {
233
+ (Area(-10.0, 10.0, 0.0, 0.0), 42),
234
+ (Area(0.0, 0.0, 10, -10), 43)
235
+ }
236
+ make_vectors_with_mutlile_ids(areas, path)
237
+
238
+ burn_value = 2
239
+ layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
240
+ layer2_total = layer2.sum()
241
+ assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
242
+
243
+ calc = layer1 * layer2
244
+
245
+ assert calc.area == layer1.area
246
+
247
+ result = RasterLayer.empty_raster_layer_like(calc)
248
+ calc.save(result)
249
+ actual = result.read_array(0, 0, 2, 2)
250
+
251
+ expected = np.array([[2, 0], [0, 8]])
252
+ assert (expected == actual).all()
253
+
254
+ @pytest.mark.skipif(yirgacheffe.backends.BACKEND != "NUMPY", reason="Only applies for numpy")
255
+ def test_parallel_save_windows() -> None:
256
+ data1 = np.array([[1, 2], [3, 4]])
257
+ data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
258
+
259
+ with tempfile.TemporaryDirectory() as tempdir:
260
+ layer1_filename = os.path.join(tempdir, "layer1.tif")
261
+ layer1_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1, filename=layer1_filename)
262
+ layer1_dataset.Close()
263
+
264
+ layer2_filename = os.path.join(tempdir, "layer2.tif")
265
+ layer2_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data2, filename=layer2_filename)
266
+ layer2_dataset.Close()
267
+
268
+ layer1 = RasterLayer.layer_from_file(layer1_filename)
269
+ layer2 = RasterLayer.layer_from_file(layer2_filename)
270
+
271
+ assert layer1.area != layer2.area
272
+ assert layer1.window != layer2.window
273
+
274
+ calc = layer1 + layer2
275
+
276
+ assert calc.area == layer2.area
277
+ assert calc.window == layer2.window
278
+
279
+ result = RasterLayer.empty_raster_layer_like(calc)
280
+ calc.parallel_save(result)
281
+
282
+ expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
283
+ actual = result.read_array(0, 0, 4, 4)
284
+ assert (expected == actual).all()
@@ -0,0 +1,32 @@
1
+
2
+ import numpy as np
3
+ import yirgacheffe
4
+ from yirgacheffe.layers import RasterLayer, ConstantLayer
5
+ from yirgacheffe.operators import DataType
6
+ from yirgacheffe.window import Area, PixelScale
7
+
8
+ def test_constant_save() -> None:
9
+ area = Area(left=-1.0, right=1.0, top=1.0, bottom=-1.0)
10
+ scale = PixelScale(0.1, -0.1)
11
+ with RasterLayer.empty_raster_layer(area, scale, DataType.Float32) as result:
12
+ with ConstantLayer(42.0) as c:
13
+ c.save(result)
14
+
15
+ expected = np.full((20, 20), 42.0)
16
+ actual = result.read_array(0, 0, 20, 20)
17
+
18
+ assert (expected == actual).all()
19
+
20
+ def test_constant_parallel_save(monkeypatch) -> None:
21
+ area = Area(left=-1.0, right=1.0, top=1.0, bottom=-1.0)
22
+ scale = PixelScale(0.1, -0.1)
23
+ with RasterLayer.empty_raster_layer(area, scale, DataType.Float32) as result:
24
+ with ConstantLayer(42.0) as c:
25
+ with monkeypatch.context() as m:
26
+ m.setattr(yirgacheffe.constants, "YSTEP", 1)
27
+ c.parallel_save(result)
28
+
29
+ expected = np.full((20, 20), 42.0)
30
+ actual = result.read_array(0, 0, 20, 20)
31
+
32
+ assert (expected == actual).all()
@@ -0,0 +1,67 @@
1
+
2
+ import numpy as np
3
+ import pytest
4
+ from osgeo import gdal
5
+
6
+ from yirgacheffe.operators import DataType
7
+ from yirgacheffe.backends import backend, BACKEND
8
+ from yirgacheffe.layers import RasterLayer
9
+
10
+ from tests.helpers import gdal_dataset_with_data
11
+
12
+ @pytest.mark.parametrize("gtype", [
13
+ gdal.GDT_Int8,
14
+ gdal.GDT_Int16,
15
+ gdal.GDT_Int32,
16
+ gdal.GDT_Int64,
17
+ gdal.GDT_Byte,
18
+ gdal.GDT_UInt16,
19
+ gdal.GDT_UInt32,
20
+ gdal.GDT_UInt64,
21
+ gdal.GDT_Float32,
22
+ ])
23
+ def test_round_trip(gtype) -> None:
24
+ ytype = DataType.of_gdal(gtype)
25
+ backend_type = backend.dtype_to_backed(ytype)
26
+ assert backend.backend_to_dtype(backend_type) == ytype
27
+
28
+ @pytest.mark.parametrize("ytype", [
29
+ DataType.Int8,
30
+ DataType.Int16,
31
+ DataType.Int32,
32
+ DataType.Int64,
33
+ DataType.UInt8,
34
+ DataType.UInt16,
35
+ DataType.UInt32,
36
+ DataType.UInt64,
37
+ DataType.Float32,
38
+ DataType.Float64,
39
+ ])
40
+ def test_round_trip_from_gdal(ytype) -> None:
41
+ gtype = ytype.to_gdal()
42
+ assert DataType.of_gdal(gtype) == ytype
43
+
44
+ def test_round_trip_float64() -> None:
45
+ backend_type = backend.dtype_to_backed(DataType.Float64)
46
+ ytype = backend.backend_to_dtype(backend_type)
47
+ print(BACKEND, "sad")
48
+ match BACKEND:
49
+ case "NUMPY":
50
+ assert ytype == DataType.Float64
51
+ case "MLX":
52
+ assert ytype == DataType.Float32
53
+
54
+ def test_float_to_int() -> None:
55
+ data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.5, 6.5, 7.5, 8.5]])
56
+
57
+ layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
58
+ # Note the float 32 here is to rule out that writing the result to the
59
+ # new dataset was what caused the truncation
60
+ result = RasterLayer.empty_raster_layer_like(layer1, datatype=DataType.Float32)
61
+
62
+ comp = layer1.astype(DataType.UInt8)
63
+ comp.save(result)
64
+
65
+ expected = backend.promote(np.array([[1, 2, 3, 4], [5, 6, 7, 8]]))
66
+ actual = backend.demote_array(result.read_array(0, 0, 4, 2))
67
+ assert (expected == actual).all()
@@ -5,7 +5,7 @@ import tempfile
5
5
  import numpy as np
6
6
  import pytest
7
7
 
8
- from helpers import gdal_dataset_of_region, gdal_dataset_with_data, make_vectors_with_id, generate_child_tile
8
+ from tests.helpers import gdal_dataset_of_region, gdal_dataset_with_data, make_vectors_with_id, generate_child_tile
9
9
  from yirgacheffe import WGS_84_PROJECTION
10
10
  from yirgacheffe.layers import GroupLayer, RasterLayer, TiledGroupLayer, VectorLayer
11
11
  from yirgacheffe.window import Area, PixelScale, Window
@@ -35,7 +35,7 @@ def test_valid_file_list():
35
35
  assert group.area == area
36
36
  assert group.window == Window(0, 0, 100, 100)
37
37
 
38
- def test_valid_file_list():
38
+ def test_valid_file_list_from_dir():
39
39
  with tempfile.TemporaryDirectory() as tempdir:
40
40
  path = os.path.join(tempdir, "test.tif")
41
41
  area = Area(-10, 10, 10, -10)
@@ -221,8 +221,8 @@ def test_with_window_adjust(klass):
221
221
 
222
222
  # Test before we apply a window
223
223
  row = group.read_array(0, 0, 100, 1)[0]
224
- for idx in range(len(row)):
225
- assert row[idx] == math.ceil((idx + 1) / 10.0)
224
+ for idx, val in enumerate(row):
225
+ assert val == math.ceil((idx + 1) / 10.0)
226
226
 
227
227
  # Test also for manual offsets that we get expected result
228
228
  for idx in range(0, 10):
@@ -6,9 +6,11 @@ from osgeo import gdal
6
6
  from yirgacheffe import WGS_84_PROJECTION
7
7
  from yirgacheffe.layers import RasterLayer, H3CellLayer
8
8
  from yirgacheffe.window import Area, PixelScale
9
- from yirgacheffe.operators import ShaderStyleOperation
10
9
  from yirgacheffe.backends import backend
11
10
 
11
+ # work around of pylint
12
+ demote_array = backend.demote_array
13
+
12
14
 
13
15
  @pytest.mark.parametrize(
14
16
  "cell_id,is_valid,expected_zoom",
@@ -135,10 +137,10 @@ def test_h3_layer_clipped(lat: float, lng: float) -> None:
135
137
 
136
138
  # whilst we're here, check that we do have an filled border (i.e., does window for
137
139
  # intersection do the right thing)
138
- assert np.sum(backend.demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 5))) > 0.0
139
- assert np.sum(backend.demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 5, h3_layer.window.xsize, 5))) > 0.0
140
- assert np.sum(backend.demote_array(h3_layer.read_array(0, 0, 5, h3_layer.window.ysize))) > 0.0
141
- assert np.sum(backend.demote_array(h3_layer.read_array(h3_layer.window.xsize - 5, 0, 5, h3_layer.window.ysize))) > 0.0
140
+ assert np.sum(demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 5))) > 0.0
141
+ assert np.sum(demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 5, h3_layer.window.xsize, 5))) > 0.0
142
+ assert np.sum(demote_array(h3_layer.read_array(0, 0, 5, h3_layer.window.ysize))) > 0.0
143
+ assert np.sum(demote_array(h3_layer.read_array(h3_layer.window.xsize - 5, 0, 5, h3_layer.window.ysize))) > 0.0
142
144
 
143
145
  @pytest.mark.parametrize(
144
146
  "lat,lng",
@@ -189,8 +191,8 @@ def test_h3_layer_wrapped_on_projection(lat: float, lng: float) -> None:
189
191
  assert expanded_area == area
190
192
 
191
193
  # whilst we're here, check that we do have an empty border (i.e., does window for union do the right thing)
192
- assert np.sum(backend.demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 2))) == 0.0
193
- assert np.sum(backend.demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 2, h3_layer.window.xsize, 2))) == 0.0
194
+ assert np.sum(demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 2))) == 0.0
195
+ assert np.sum(demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 2, h3_layer.window.xsize, 2))) == 0.0
194
196
 
195
197
  def test_h3_layer_overlapped():
196
198
  # This is based on a regression, where somehow I made tiles not tesselate properly
@@ -1,7 +1,7 @@
1
1
  import pytest
2
2
  from osgeo import gdal
3
3
 
4
- from helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
4
+ from tests.helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
5
5
  from yirgacheffe.window import Area, PixelScale, Window
6
6
  from yirgacheffe.layers import RasterLayer, ConstantLayer
7
7
  from yirgacheffe.h3layer import H3CellLayer
@@ -4,7 +4,7 @@ import tempfile
4
4
  import numpy as np
5
5
  from osgeo import gdal
6
6
 
7
- from helpers import gdal_dataset_with_data
7
+ from tests.helpers import gdal_dataset_with_data
8
8
  from yirgacheffe.layers import RasterLayer
9
9
  from yirgacheffe.window import Area, PixelScale
10
10
 
@@ -52,7 +52,7 @@ def test_stack_tifs_with_area_match() -> None:
52
52
  for layer in source_layers:
53
53
  layer.set_window_for_intersection(intersection)
54
54
 
55
- # Note we're abusing that layer is the last of the source_layers here from the above loop
55
+ layer = source_layers[-1]
56
56
  assert layer.window.xsize == 100 - (bands - 1)
57
57
  assert layer.window.ysize == 100 - (bands - 1)
58
58
 
@@ -5,13 +5,12 @@ import tempfile
5
5
  import numpy as np
6
6
  import pytest
7
7
  import torch
8
- from osgeo import gdal
9
8
 
10
- from helpers import gdal_dataset_with_data
11
9
  import yirgacheffe
12
10
  from yirgacheffe.layers import RasterLayer, ConstantLayer
13
11
  from yirgacheffe.operators import LayerOperation, DataType
14
12
  from yirgacheffe.backends import backend
13
+ from tests.helpers import gdal_dataset_with_data
15
14
 
16
15
  def test_add_byte_layers() -> None:
17
16
  data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
@@ -71,7 +70,7 @@ def test_add_byte_layers_with_callback(skip, expected_steps) -> None:
71
70
 
72
71
  comp = layer1 + layer2
73
72
  comp.ystep = skip
74
- comp.save(result, callback=lambda x: callback_possitions.append(x))
73
+ comp.save(result, callback=callback_possitions.append)
75
74
 
76
75
  expected = data1 + data2
77
76
  actual = result.read_array(0, 0, 4, 2)
@@ -5,7 +5,7 @@ import pytest
5
5
 
6
6
  from yirgacheffe import WGS_84_PROJECTION
7
7
  from yirgacheffe.h3layer import H3CellLayer
8
- from yirgacheffe.layers import PixelScale, ConstantLayer, RasterLayer
8
+ from yirgacheffe.layers import PixelScale, RasterLayer
9
9
  from yirgacheffe.window import Area
10
10
  import yirgacheffe.operators as yo
11
11
 
@@ -14,7 +14,7 @@ class NaiveH3CellLayer(H3CellLayer):
14
14
  so the H3CellLayer has a bunch of tricks to try reduce the work done. This is a naive
15
15
  version that checks for every cell."""
16
16
 
17
- def read_array(self, xoffset, yoffset, xsize, ysize):
17
+ def read_array(self, xoffset, yoffset, xsize, ysize): # pylint: disable=W0237
18
18
  res = np.zeros((ysize, xsize), dtype=float)
19
19
  start_x = self._active_area.left + (xoffset * self._pixel_scale.xstep)
20
20
  start_y = self._active_area.top + (yoffset * self._pixel_scale.ystep)
@@ -6,8 +6,8 @@ import pytest
6
6
  import torch
7
7
 
8
8
  import yirgacheffe
9
- from helpers import gdal_dataset_with_data
10
- from yirgacheffe.layers import RasterLayer, ConstantLayer
9
+ from tests.helpers import gdal_dataset_with_data
10
+ from yirgacheffe.layers import RasterLayer
11
11
  from yirgacheffe.operators import LayerOperation
12
12
 
13
13
  # These tests are marked skip for MLX, because there seems to be a problem with
@@ -153,7 +153,7 @@ def test_parallel_with_different_skip(monkeypatch, skip, expected_steps) -> None
153
153
 
154
154
  comp = layer1 + layer2
155
155
  comp.ystep = skip
156
- comp.parallel_save(result, callback=lambda x: callback_possitions.append(x))
156
+ comp.parallel_save(result, callback=callback_possitions.append)
157
157
 
158
158
  expected = data1 + data2
159
159
  actual = result.read_array(0, 0, 4, 4)
@@ -7,9 +7,10 @@ import tempfile
7
7
  import numpy as np
8
8
  import pytest
9
9
 
10
- from helpers import gdal_dataset_of_region, make_vectors_with_id
10
+ from tests.helpers import gdal_dataset_of_region, make_vectors_with_id
11
11
  from yirgacheffe.window import Area, PixelScale, Window
12
- from yirgacheffe.layers import ConstantLayer, GroupLayer, RasterLayer, RescaledRasterLayer, UniformAreaLayer, VectorLayer
12
+ from yirgacheffe.layers import ConstantLayer, GroupLayer, RasterLayer, RescaledRasterLayer, \
13
+ UniformAreaLayer, VectorLayer
13
14
  from yirgacheffe import WGS_84_PROJECTION
14
15
  from yirgacheffe.backends import backend
15
16
 
@@ -5,7 +5,7 @@ import numpy as np
5
5
  import pytest
6
6
  from osgeo import gdal
7
7
 
8
- from helpers import gdal_dataset_of_region, gdal_multiband_dataset_with_data
8
+ from tests.helpers import gdal_dataset_of_region, gdal_multiband_dataset_with_data
9
9
  from yirgacheffe.window import Area, PixelScale, Window
10
10
  from yirgacheffe.layers import RasterLayer, InvalidRasterBand
11
11
  from yirgacheffe.rounding import round_up_pixels
@@ -39,7 +39,7 @@ def test_make_basic_layer() -> None:
39
39
  assert close_called
40
40
 
41
41
  def test_make_basic_layer_old_name() -> None:
42
- from yirgacheffe.layers import Layer
42
+ from yirgacheffe.layers import Layer # pylint: disable=C0415
43
43
 
44
44
  area = Area(-10, 10, 10, -10)
45
45
  with Layer(gdal_dataset_of_region(area, 0.02)) as layer:
@@ -104,7 +104,7 @@ def test_empty_layer_from_raster():
104
104
  assert empty.window == source.window
105
105
  assert empty.datatype == source.datatype
106
106
  assert empty.geo_transform == source.geo_transform
107
- assert empty._dataset.GetRasterBand(1).GetNoDataValue() == None
107
+ assert empty._dataset.GetRasterBand(1).GetNoDataValue() is None
108
108
 
109
109
  @pytest.mark.parametrize("nodata", [0, 0.0, 2, 2.0])
110
110
  def test_empty_layer_from_raster_with_no_data_value(nodata):
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
 
3
- from helpers import gdal_dataset_of_region, gdal_dataset_with_data
3
+ from tests.helpers import gdal_dataset_of_region, gdal_dataset_with_data
4
4
  from yirgacheffe.layers import RasterLayer, RescaledRasterLayer
5
5
  from yirgacheffe.window import Area, PixelScale, Window
6
6
 
@@ -1,6 +1,6 @@
1
1
  import numpy
2
2
 
3
- from helpers import gdal_dataset_with_data
3
+ from tests.helpers import gdal_dataset_with_data
4
4
  from yirgacheffe.layers import RasterLayer
5
5
 
6
6
  def test_add_byte_layers_with_union() -> None:
@@ -1,6 +1,6 @@
1
1
  import numpy
2
2
 
3
- from helpers import gdal_dataset_with_data
3
+ from tests.helpers import gdal_dataset_with_data
4
4
  from yirgacheffe.layers import RasterLayer
5
5
 
6
6
 
@@ -4,7 +4,7 @@ from math import ceil, floor
4
4
 
5
5
  import pytest
6
6
 
7
- from helpers import gdal_dataset_of_region
7
+ from tests.helpers import gdal_dataset_of_region
8
8
  from yirgacheffe.layers import UniformAreaLayer
9
9
  from yirgacheffe.window import Area, Window
10
10
 
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- from helpers import gdal_dataset_of_region
3
+ from tests.helpers import gdal_dataset_of_region
4
4
  from yirgacheffe.window import Area, Window
5
5
  from yirgacheffe.layers import ConstantLayer, RasterLayer
6
6
 
@@ -2,9 +2,8 @@ import os
2
2
  import tempfile
3
3
 
4
4
  import pytest
5
- from osgeo import gdal
6
5
 
7
- from helpers import make_vectors_with_mutlile_ids, make_vectors_with_id, make_vectors_with_empty_feature
6
+ from tests.helpers import make_vectors_with_mutlile_ids, make_vectors_with_id, make_vectors_with_empty_feature
8
7
  from yirgacheffe import WGS_84_PROJECTION
9
8
  from yirgacheffe.layers import RasterLayer, RasteredVectorLayer, VectorLayer, VectorRangeLayer, DynamicVectorRangeLayer
10
9
  from yirgacheffe.window import Area, PixelScale, Window
@@ -111,7 +110,12 @@ def test_empty_layer_from_vector():
111
110
  area = Area(left=44.00253688814017, top=-12.440948032828079, right=50.483612168477286, bottom=-25.1535466075739)
112
111
  make_vectors_with_id(42, {area}, path)
113
112
 
114
- source = VectorLayer.layer_from_file(path, "id_no = 42", PixelScale(xstep=0.00026949458523585647, ystep=-0.00026949458523585647), WGS_84_PROJECTION)
113
+ source = VectorLayer.layer_from_file(
114
+ path,
115
+ "id_no = 42",
116
+ PixelScale(xstep=0.00026949458523585647, ystep=-0.00026949458523585647),
117
+ WGS_84_PROJECTION
118
+ )
115
119
 
116
120
  empty = RasterLayer.empty_raster_layer_like(source)
117
121
  assert empty.pixel_scale == source.pixel_scale
@@ -422,7 +426,13 @@ def test_anchor_offsets(anchor, area, expected):
422
426
  path = os.path.join(tempdir, "test.gpkg")
423
427
  make_vectors_with_id(42, {area}, path)
424
428
 
425
- source = VectorLayer.layer_from_file(path, "id_no = 42", PixelScale(1.0, -1.0), WGS_84_PROJECTION, anchor=anchor)
429
+ source = VectorLayer.layer_from_file(
430
+ path,
431
+ "id_no = 42",
432
+ PixelScale(1.0, -1.0),
433
+ WGS_84_PROJECTION,
434
+ anchor=anchor
435
+ )
426
436
 
427
437
  final_area = source.area
428
438
  assert final_area == expected
@@ -521,9 +521,17 @@ class LayerOperation(LayerMathMixin):
521
521
  except AttributeError as exc:
522
522
  raise ValueError("Layer must be a raster backed layer") from exc
523
523
 
524
- computation_window = self.window
525
524
  destination_window = destination_layer.window
526
525
 
526
+ # If we're calculating purely from a constant layer, then we don't have a window or area
527
+ # so we should use the destination raster details.
528
+ try:
529
+ computation_window = self.window
530
+ computation_area = self.area
531
+ except AttributeError:
532
+ computation_window = destination_window
533
+ computation_area = destination_layer.area
534
+
527
535
  if (computation_window.xsize != destination_window.xsize) \
528
536
  or (computation_window.ysize != destination_window.ysize):
529
537
  raise ValueError("Destination raster window size does not match input raster window size.")
@@ -536,7 +544,7 @@ class LayerOperation(LayerMathMixin):
536
544
  step=self.ystep
537
545
  if yoffset+step > computation_window.ysize:
538
546
  step = computation_window.ysize - yoffset
539
- chunk = self._eval(self.area, yoffset, step, computation_window)
547
+ chunk = self._eval(computation_area, yoffset, step, computation_window)
540
548
  if isinstance(chunk, (float, int)):
541
549
  chunk = backend.full((step, destination_window.xsize), chunk)
542
550
  band.WriteArray(
@@ -599,7 +607,18 @@ class LayerOperation(LayerMathMixin):
599
607
 
600
608
  def _parallel_save(self, destination_layer, and_sum=False, callback=None, parallelism=None, band=1):
601
609
  assert (destination_layer is not None) or and_sum
602
- computation_window = self.window
610
+ try:
611
+ computation_window = self.window
612
+ except AttributeError:
613
+ # This is most likely because the calculation is on a constant layer (or combination of only constant
614
+ # layers) and there's no real benefit to parallel saving then, so to keep this code from getting yet
615
+ # more complicated just fall back to the single threaded path
616
+ if destination_layer:
617
+ return self.save(destination_layer, and_sum, callback, band)
618
+ elif and_sum:
619
+ return self.sum()
620
+ else:
621
+ assert False
603
622
 
604
623
  worker_count = parallelism or multiprocessing.cpu_count()
605
624
  work_blocks = len(range(0, computation_window.ysize, self.ystep))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yirgacheffe
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: Abstraction of gdal datasets for doing basic math operations
5
5
  Author-email: Michael Dales <mwd24@cam.ac.uk>
6
6
  License-Expression: ISC
@@ -5,6 +5,7 @@ pyproject.toml
5
5
  tests/test_area.py
6
6
  tests/test_auto_windowing.py
7
7
  tests/test_base.py
8
+ tests/test_constants.py
8
9
  tests/test_datatypes.py
9
10
  tests/test_group.py
10
11
  tests/test_h3layer.py
@@ -1,21 +0,0 @@
1
- import pytest
2
-
3
- # I've no idea why pylint dislikes this particular import but accepts
4
- # other entries in the module.
5
- from yirgacheffe.window import Area # pylint: disable=E0401, E0611
6
-
7
- @pytest.mark.parametrize(
8
- "lhs,rhs,is_equal,overlaps",
9
- [
10
- # Obvious equality
11
- (Area(-10.0, 10.0, 10.0, -10.0), Area(-10.0, 10.0, 10.0, -10.0), True, True),
12
- (Area(-9.0, 9.0, 9.0, -9.0), Area(-10.0, 10.0, 10.0, -10.0), False, True), # subset
13
- (Area(-9.0, 9.0, -1.0, 1.0), Area(1.0, -1.0, 9.0, -9.0), False, False),
14
- (Area(-10.0, 10.0, 1.0, -10.0), Area(-1.0, 10.0, 10.0, -10.0), False, True),
15
- ]
16
- )
17
- def test_area_operators(lhs: Area, rhs: Area, is_equal: bool, overlaps: bool) -> None:
18
- assert (lhs == rhs) == is_equal
19
- assert (lhs != rhs) == (not is_equal)
20
- assert (lhs.overlaps(rhs)) == overlaps
21
- assert (rhs.overlaps(lhs)) == overlaps
@@ -1,284 +0,0 @@
1
- import os
2
- import tempfile
3
-
4
- import numpy as np
5
- import pytest
6
-
7
- import yirgacheffe
8
- from helpers import gdal_dataset_with_data, make_vectors_with_mutlile_ids
9
- from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer, area
10
- from yirgacheffe.window import Area
11
-
12
- def test_add_windows() -> None:
13
- data1 = np.array([[1, 2], [3, 4]])
14
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
15
-
16
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
17
- layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
18
-
19
- assert layer1.area != layer2.area
20
- assert layer1.window != layer2.window
21
-
22
- calc = layer1 + layer2
23
-
24
- assert calc.area == layer2.area
25
- assert calc.window == layer2.window
26
-
27
- result = RasterLayer.empty_raster_layer_like(calc)
28
- calc.save(result)
29
-
30
- expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
31
- actual = result.read_array(0, 0, 4, 4)
32
- assert (expected == actual).all()
33
-
34
- def test_multiply_windows() -> None:
35
- data1 = np.array([[1, 2], [3, 4]])
36
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
37
-
38
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
39
- layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
40
-
41
- assert layer1.area != layer2.area
42
- assert layer1.window != layer2.window
43
-
44
- calc = layer1 * layer2
45
-
46
- assert calc.area == layer1.area
47
- assert calc.window == layer1.window
48
-
49
- result = RasterLayer.empty_raster_layer_like(calc)
50
- calc.save(result)
51
-
52
- expected = np.array([[10, 40], [150, 240]])
53
- actual = result.read_array(0, 0, 2, 2)
54
- assert (expected == actual).all()
55
-
56
- def test_add_windows_offset() -> None:
57
- data1 = np.array([[1, 2], [3, 4]])
58
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
59
-
60
- layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
61
- layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
62
-
63
- assert layer1.area != layer2.area
64
- assert layer1.window != layer2.window
65
-
66
- calc = layer1 + layer2
67
-
68
- assert calc.area == layer2.area
69
-
70
- result = RasterLayer.empty_raster_layer_like(calc)
71
- calc.save(result)
72
-
73
- expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
74
- actual = result.read_array(0, 0, 4, 4)
75
- assert (expected == actual).all()
76
-
77
- def test_multiply_windows_offset() -> None:
78
- data1 = np.array([[1, 2], [3, 4]])
79
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
80
-
81
- layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
82
- layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
83
-
84
- assert layer1.area != layer2.area
85
- assert layer1.window != layer2.window
86
-
87
- calc = layer1 * layer2
88
-
89
- assert calc.area == layer1.area
90
-
91
- result = RasterLayer.empty_raster_layer_like(calc)
92
- calc.save(result)
93
-
94
- expected = np.array([[60, 140], [300, 440]])
95
- actual = result.read_array(0, 0, 2, 2)
96
- assert (expected == actual).all()
97
-
98
- def test_add_windows_sum() -> None:
99
- data1 = np.array([[1, 2], [3, 4]])
100
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
101
-
102
- layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
103
- layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
104
-
105
- calc = layer1 + layer2
106
- total = calc.sum()
107
-
108
- expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
109
- assert total == np.sum(expected)
110
-
111
- def test_multiply_windows_sum() -> None:
112
- data1 = np.array([[1, 2], [3, 4]])
113
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
114
-
115
- layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
116
- layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
117
-
118
- calc = layer1 * layer2
119
- total = calc.sum()
120
-
121
- expected = np.array([[60, 140], [300, 440]])
122
- assert total == np.sum(expected)
123
-
124
- def test_constant_layer_result_rhs_add() -> None:
125
- data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
126
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
127
- const_layer = ConstantLayer(1.0)
128
-
129
- calc = layer1 + const_layer
130
-
131
- assert calc.area == layer1.area
132
-
133
- result = RasterLayer.empty_raster_layer_like(calc)
134
- calc.save(result)
135
- actual = result.read_array(0, 0, 4, 2)
136
-
137
- expected = 1.0 + data1
138
-
139
- assert (expected == actual).all()
140
-
141
- def test_constant_layer_result_lhs_add() -> None:
142
- data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
143
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
144
- const_layer = ConstantLayer(1.0)
145
- result = RasterLayer.empty_raster_layer_like(layer1)
146
-
147
- intersection = RasterLayer.find_intersection([layer1, const_layer])
148
- const_layer.set_window_for_intersection(intersection)
149
- layer1.set_window_for_intersection(intersection)
150
-
151
- calc = const_layer + layer1
152
-
153
- assert calc.area == layer1.area
154
-
155
- result = RasterLayer.empty_raster_layer_like(calc)
156
- calc.save(result)
157
- actual = result.read_array(0, 0, 4, 2)
158
-
159
- expected = 1.0 + data1
160
-
161
- assert (expected == actual).all()
162
-
163
- def test_constant_layer_result_rhs_multiply() -> None:
164
- data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
165
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
166
- const_layer = ConstantLayer(2.0)
167
-
168
- calc = layer1 * const_layer
169
-
170
- assert calc.area == layer1.area
171
-
172
- result = RasterLayer.empty_raster_layer_like(calc)
173
- calc.save(result)
174
- actual = result.read_array(0, 0, 4, 2)
175
-
176
- expected = data1 * 2.0
177
-
178
- assert (expected == actual).all()
179
-
180
- def test_constant_layer_result_lhs_multiply() -> None:
181
- data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
182
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
183
- const_layer = ConstantLayer(2.0)
184
- result = RasterLayer.empty_raster_layer_like(layer1)
185
-
186
- intersection = RasterLayer.find_intersection([layer1, const_layer])
187
- const_layer.set_window_for_intersection(intersection)
188
- layer1.set_window_for_intersection(intersection)
189
-
190
- calc = const_layer * layer1
191
-
192
- assert calc.area == layer1.area
193
-
194
- result = RasterLayer.empty_raster_layer_like(calc)
195
- calc.save(result)
196
- actual = result.read_array(0, 0, 4, 2)
197
-
198
- expected = 2.0 * data1
199
-
200
- assert (expected == actual).all()
201
-
202
- def test_vector_layers_add() -> None:
203
- data1 = np.array([[1, 2], [3, 4]])
204
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 1.0, data1))
205
-
206
- with tempfile.TemporaryDirectory() as tempdir:
207
- path = os.path.join(tempdir, "test.gpkg")
208
- areas = {
209
- (Area(-10.0, 10.0, 0.0, 0.0), 42),
210
- (Area(0.0, 0.0, 10, -10), 43)
211
- }
212
- make_vectors_with_mutlile_ids(areas, path)
213
-
214
- burn_value = 2
215
- layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
216
- layer2_total = layer2.sum()
217
- assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
218
-
219
- calc = layer1 + layer2
220
-
221
- assert calc.area == layer2.area
222
-
223
- total = calc.sum()
224
- assert total == layer2_total + np.sum(data1)
225
-
226
- def test_vector_layers_multiply() -> None:
227
- data1 = np.array([[1, 2], [3, 4]])
228
- layer1 = RasterLayer(gdal_dataset_with_data((-1.0, 1.0), 1.0, data1))
229
-
230
- with tempfile.TemporaryDirectory() as tempdir:
231
- path = os.path.join(tempdir, "test.gpkg")
232
- areas = {
233
- (Area(-10.0, 10.0, 0.0, 0.0), 42),
234
- (Area(0.0, 0.0, 10, -10), 43)
235
- }
236
- make_vectors_with_mutlile_ids(areas, path)
237
-
238
- burn_value = 2
239
- layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
240
- layer2_total = layer2.sum()
241
- assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
242
-
243
- calc = layer1 * layer2
244
-
245
- assert calc.area == layer1.area
246
-
247
- result = RasterLayer.empty_raster_layer_like(calc)
248
- calc.save(result)
249
- actual = result.read_array(0, 0, 2, 2)
250
-
251
- expected = np.array([[2, 0], [0, 8]])
252
- assert (expected == actual).all()
253
-
254
- @pytest.mark.skipif(yirgacheffe.backends.BACKEND != "NUMPY", reason="Only applies for numpy")
255
- def test_parallel_save_windows() -> None:
256
- data1 = np.array([[1, 2], [3, 4]])
257
- data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
258
-
259
- with tempfile.TemporaryDirectory() as tempdir:
260
- layer1_filename = os.path.join(tempdir, "layer1.tif")
261
- layer1_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1, filename=layer1_filename)
262
- layer1_dataset.Close()
263
-
264
- layer2_filename = os.path.join(tempdir, "layer2.tif")
265
- layer2_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data2, filename=layer2_filename)
266
- layer2_dataset.Close()
267
-
268
- layer1 = RasterLayer.layer_from_file(layer1_filename)
269
- layer2 = RasterLayer.layer_from_file(layer2_filename)
270
-
271
- assert layer1.area != layer2.area
272
- assert layer1.window != layer2.window
273
-
274
- calc = layer1 + layer2
275
-
276
- assert calc.area == layer2.area
277
- assert calc.window == layer2.window
278
-
279
- result = RasterLayer.empty_raster_layer_like(calc)
280
- calc.parallel_save(result)
281
-
282
- expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
283
- actual = result.read_array(0, 0, 4, 4)
284
- assert (expected == actual).all()
@@ -1,67 +0,0 @@
1
-
2
- import numpy as np
3
- import pytest
4
- from osgeo import gdal
5
-
6
- from yirgacheffe.operators import DataType
7
- from yirgacheffe.backends import backend, BACKEND
8
- from yirgacheffe.layers import RasterLayer
9
-
10
- from helpers import gdal_dataset_with_data
11
-
12
- @pytest.mark.parametrize("gtype", [
13
- gdal.GDT_Int8,
14
- gdal.GDT_Int16,
15
- gdal.GDT_Int32,
16
- gdal.GDT_Int64,
17
- gdal.GDT_Byte,
18
- gdal.GDT_UInt16,
19
- gdal.GDT_UInt32,
20
- gdal.GDT_UInt64,
21
- gdal.GDT_Float32,
22
- ])
23
- def test_round_trip(gtype) -> None:
24
- ytype = DataType.of_gdal(gtype)
25
- backend_type = backend.dtype_to_backed(ytype)
26
- assert backend.backend_to_dtype(backend_type) == ytype
27
-
28
- @pytest.mark.parametrize("ytype", [
29
- DataType.Int8,
30
- DataType.Int16,
31
- DataType.Int32,
32
- DataType.Int64,
33
- DataType.UInt8,
34
- DataType.UInt16,
35
- DataType.UInt32,
36
- DataType.UInt64,
37
- DataType.Float32,
38
- DataType.Float64,
39
- ])
40
- def test_round_trip_from_gdal(ytype) -> None:
41
- gtype = ytype.to_gdal()
42
- assert DataType.of_gdal(gtype) == ytype
43
-
44
- def test_round_trip_float64() -> None:
45
- backend_type = backend.dtype_to_backed(DataType.Float64)
46
- ytype = backend.backend_to_dtype(backend_type)
47
- print(BACKEND, "sad")
48
- match BACKEND:
49
- case "NUMPY":
50
- assert ytype == DataType.Float64
51
- case "MLX":
52
- assert ytype == DataType.Float32
53
-
54
- def test_float_to_int() -> None:
55
- data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.5, 6.5, 7.5, 8.5]])
56
-
57
- layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
58
- # Note the float 32 here is to rule out that writing the result to the
59
- # new dataset was what caused the truncation
60
- result = RasterLayer.empty_raster_layer_like(layer1, datatype=DataType.Float32)
61
-
62
- comp = layer1.astype(DataType.UInt8)
63
- comp.save(result)
64
-
65
- expected = backend.promote(np.array([[1, 2, 3, 4], [5, 6, 7, 8]]))
66
- actual = backend.demote_array(result.read_array(0, 0, 4, 2))
67
- assert (expected == actual).all()
File without changes
File without changes
File without changes
File without changes