|
1 | 1 | import numpy as np |
2 | 2 | import xarray as xr |
3 | 3 |
|
4 | | -from xrspatial.experimental import polygonize |
| 4 | +from xrspatial import polygonize |
| 5 | +from xrspatial.polygonize import ( |
| 6 | + _calculate_regions, _scan, |
| 7 | +) |
| 8 | + |
| 9 | +try: |
| 10 | + import cupy |
| 11 | + from xrspatial.polygonize import _calculate_regions_cupy |
| 12 | + _has_cupy = True |
| 13 | +except ImportError: |
| 14 | + _has_cupy = False |
5 | 15 |
|
6 | 16 |
|
7 | 17 | class Polygonize: |
@@ -40,3 +50,75 @@ def time_polygonize(self, nx, ret): |
40 | 50 | gpd.GeoDataFrame({"DN": values, "geometry": shapes}) |
41 | 51 | else: |
42 | 52 | polygonize(self.raster, mask=self.mask, return_type=ret) |
| 53 | + |
| 54 | + |
| 55 | +class PolygonizeCuPy: |
| 56 | + params = ([100, 300, 1000],) |
| 57 | + param_names = ("nx",) |
| 58 | + |
| 59 | + def setup(self, nx): |
| 60 | + if not _has_cupy: |
| 61 | + raise NotImplementedError("CuPy not available") |
| 62 | + ny = nx // 2 |
| 63 | + rng = np.random.default_rng(9461713) |
| 64 | + raster = rng.integers(low=0, high=4, size=(ny, nx), dtype=np.int32) |
| 65 | + mask = rng.uniform(0, 1, size=(ny, nx)) < 0.9 |
| 66 | + self.raster = xr.DataArray(cupy.asarray(raster)) |
| 67 | + self.mask = xr.DataArray(cupy.asarray(mask)) |
| 68 | + |
| 69 | + def time_polygonize(self, nx): |
| 70 | + polygonize(self.raster, mask=self.mask) |
| 71 | + |
| 72 | + |
| 73 | +class PolygonizeCCL: |
| 74 | + """Benchmark connected-component labeling phase.""" |
| 75 | + params = ([100, 300, 1000], ["numpy", "cupy"]) |
| 76 | + param_names = ("nx", "backend") |
| 77 | + |
| 78 | + def setup(self, nx, backend): |
| 79 | + if backend == "cupy" and not _has_cupy: |
| 80 | + raise NotImplementedError("CuPy not available") |
| 81 | + ny = nx // 2 |
| 82 | + rng = np.random.default_rng(9461713) |
| 83 | + raster = rng.integers(low=0, high=4, size=(ny, nx), dtype=np.int32) |
| 84 | + mask = (rng.uniform(0, 1, size=(ny, nx)) < 0.9) |
| 85 | + if backend == "cupy": |
| 86 | + self.data = cupy.asarray(raster) |
| 87 | + self.mask = cupy.asarray(mask) |
| 88 | + else: |
| 89 | + self.data = raster |
| 90 | + self.mask = mask |
| 91 | + self.ny, self.nx = ny, nx |
| 92 | + self.backend = backend |
| 93 | + |
| 94 | + def time_calculate_regions(self, nx, backend): |
| 95 | + if backend == "cupy": |
| 96 | + _calculate_regions_cupy(self.data, self.mask, False) |
| 97 | + cupy.cuda.Device().synchronize() |
| 98 | + else: |
| 99 | + _calculate_regions( |
| 100 | + self.data.ravel(), self.mask.ravel(), False, self.nx, self.ny) |
| 101 | + |
| 102 | + |
| 103 | +class PolygonizeTracing: |
| 104 | + """Benchmark boundary tracing phase (always CPU).""" |
| 105 | + params = ([100, 300, 1000],) |
| 106 | + param_names = ("nx",) |
| 107 | + |
| 108 | + def setup(self, nx): |
| 109 | + ny = nx // 2 |
| 110 | + rng = np.random.default_rng(9461713) |
| 111 | + raster = rng.integers(low=0, high=4, size=(ny, nx), dtype=np.int32) |
| 112 | + mask = (rng.uniform(0, 1, size=(ny, nx)) < 0.9) |
| 113 | + values_flat = raster.ravel() |
| 114 | + mask_flat = mask.ravel() |
| 115 | + self.regions = _calculate_regions( |
| 116 | + values_flat, mask_flat, False, nx, ny) |
| 117 | + self.values = values_flat |
| 118 | + self.mask = mask_flat |
| 119 | + self.nx = nx |
| 120 | + self.ny = ny |
| 121 | + |
| 122 | + def time_scan(self, nx): |
| 123 | + _scan(self.regions, self.values, self.mask, False, None, |
| 124 | + self.nx, self.ny) |
0 commit comments