diff --git a/.github/workflows/ci-tests.yaml b/.github/workflows/ci-tests.yaml index edfa83c..43f4d44 100644 --- a/.github/workflows/ci-tests.yaml +++ b/.github/workflows/ci-tests.yaml @@ -16,7 +16,7 @@ jobs: max-parallel: 1 matrix: os: [ubuntu-latest] - python-version: ['3.13'] + python-version: ['3.12', '3.13', '3.14'] name: pytest (Python ${{ matrix.python-version }}) (OS ${{ matrix.os }}) # Configure tests @@ -33,5 +33,4 @@ jobs: - name: Test with pytest run: | # not run benchmark test - pytest pytest -vv -m "not benchmark" \ No newline at end of file diff --git a/.github/workflows/publish-pypi.yaml b/.github/workflows/publish-pypi.yaml index 8a3e138..01b4e39 100644 --- a/.github/workflows/publish-pypi.yaml +++ b/.github/workflows/publish-pypi.yaml @@ -11,10 +11,10 @@ jobs: environment: pypi-publish steps: - uses: actions/checkout@main - - name: Set up Python 3.10 + - name: Set up Python 3.13 uses: actions/setup-python@v3 with: - python-version: "3.10" + python-version: "3.13" - name: Install pypa/build run: >- diff --git a/.github/workflows/publish-test-pypi.yaml b/.github/workflows/publish-test-pypi.yaml index ddce920..ddd9aaf 100644 --- a/.github/workflows/publish-test-pypi.yaml +++ b/.github/workflows/publish-test-pypi.yaml @@ -13,10 +13,10 @@ jobs: environment: pypi-publish steps: - uses: actions/checkout@main - - name: Set up Python 3.10 + - name: Set up Python 3.13 uses: actions/setup-python@v3 with: - python-version: "3.10" + python-version: "3.13" - name: Install pypa/build run: >- diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 808d664..9cbbbbf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,5 @@ exclude: 'docs|node_modules|migrations|.git|.tox' default_stages: [pre-commit] -fail_fast: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks @@ -8,6 +7,8 @@ repos: hooks: - id: trailing-whitespace files: (^|/)a/.+\.(py|html|sh|css|js)$ + - id: end-of-file-fixer + files: (^|/)a/.+\.(py|html|sh|css|js)$ - id: check-added-large-files args: ["--maxkb=2000"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a02af4..5845c18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,15 @@ Changelog ========= -v0.0.3.dev +v0.1.0 ------------------------------------------------------------ +- Reduce computational load of disaggretation by re-organising code and allowing parallelisation with dask [#18](https://github.com/modelblocks-org/gregor/pull/18). +- Add a more computationally expensive performance test, which disaggregates rooftop PV capacities in Europe, to be run locally [#18](https://github.com/modelblocks-org/gregor/pull/18). +- Add CI testing [#19](https://github.com/modelblocks-org/gregor/pull/19). +- Add more unit tests [#17](https://github.com/modelblocks-org/gregor/pull/17). +- Fix failing aggregation when polygon index is unnamed [#14](https://github.com/modelblocks-org/gregor/pull/14). +- Move to the [modelblocks-org](https://github.com/modelblocks-org). + v0.0.2 (2024-11-21) ------------------------------------------------------------ diff --git a/CITATION.cff b/CITATION.cff index 5ea2d69..c29b490 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,7 +9,7 @@ authors: title: "Gregor" type: software license: MIT -version: 0.0.3.dev +version: 0.1.0 doi: date-released: -url: "https://github.com/jnnr/gregor" \ No newline at end of file +url: "https://github.com/modelblocks-org/gregor" \ No newline at end of file diff --git a/README.md b/README.md index 20aa3cf..526a75f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Gregor is a tool that makes your life easier when aggregating and dis-aggregating spatial data. It has been developed in the context of preparing data for energy system modeling, but can be applied in any situation involving spatial data. - + ## Installation @@ -20,4 +20,4 @@ Please have a look at the examples presented in the [documentation](https://greg ## Development -If you encounter a bug, consider opening an issue on [GitHub](https://github.com/jnnr/gregor/issues). +If you encounter a bug, consider opening an issue on [GitHub](https://github.com/modelblocks-org/gregor/issues). diff --git a/docs/api.md b/docs/api.md index 335d15e..f25b668 100644 --- a/docs/api.md +++ b/docs/api.md @@ -5,7 +5,3 @@ ::: gregor.disaggregate options: show_source: false - -::: gregor.raster - options: - show_source: false \ No newline at end of file diff --git a/docs/examples/disaggregate-to-point.py b/docs/examples/disaggregate-to-point.py index b6ce92e..d2ca863 100644 --- a/docs/examples/disaggregate-to-point.py +++ b/docs/examples/disaggregate-to-point.py @@ -58,7 +58,7 @@ plt.show() # %% [markdown] -# Now, we disaggregate the demand data using the population data as a proxy. The result is a raster dataset with the resolution of the proxy. +# Now, we disaggregate the demand data using the population data as a proxy. The result is a raster with the resolution of the proxy. # %% demand_point = gregor.disaggregate.disaggregate_polygon_to_point(demand_geo, "FC_OTH_HH_E", cities, "pop_max") diff --git a/docs/examples/disaggregate-to-raster.py b/docs/examples/disaggregate-to-raster.py index a04fc24..d43b38f 100644 --- a/docs/examples/disaggregate-to-raster.py +++ b/docs/examples/disaggregate-to-raster.py @@ -64,7 +64,7 @@ plt.show() # %% [markdown] -# Now, we disaggregate the demand data using the population data as a proxy. The result is a raster dataset with the resolution of the proxy. +# Now, we disaggregate the demand data using the population data as a proxy. The result is a raster with the resolution of the proxy. # %% demand_raster = gregor.disaggregate.disaggregate_polygon_to_raster(demand_geo, column="FC_OTH_HH_E", proxy=population) diff --git a/pyproject.toml b/pyproject.toml index b727b12..d3e43c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,16 +5,15 @@ authors = [ ] description = "A library for spatial aggregation and disaggregation" readme = "README.md" -version = "0.0.3.dev" +version = "0.1.0" dynamic = ["dependencies", "optional-dependencies"] # complete classifier list: # http://pypi.org/classifiers/ classifiers = [ - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', ] keywords = [ @@ -24,9 +23,9 @@ keywords = [ requires-python = ">=3.8, <4" [project.urls] -changelog = "https://github.com/jnnr/gregor/blob/main/CHANGELOG.md" +changelog = "https://github.com/modelblocks-org/gregor/blob/main/CHANGELOG.md" homepage = "https://gregor.readthedocs.io/en/latest/" -repository = "https://github.com/jnnr/gregor.git" +repository = "https://github.com/modelblocks-org/gregor.git" [build-system] build-backend = "setuptools.build_meta" diff --git a/src/gregor/disaggregate.py b/src/gregor/disaggregate.py index b08cc4f..10cfb8c 100644 --- a/src/gregor/disaggregate.py +++ b/src/gregor/disaggregate.py @@ -1,3 +1,6 @@ +import logging +import warnings + import dask.array as da import geopandas as gpd import numpy as np @@ -8,6 +11,9 @@ from gregor.aggregate import aggregate_raster_to_polygon +logger = logging.getLogger(__name__) + + def disaggregate_polygon_to_raster( data: gpd.GeoDataFrame, column: str, @@ -38,8 +44,10 @@ def disaggregate_polygon_to_raster( _proxy = proxy elif isinstance(proxy, xr.Dataset): if len(proxy.data_vars) == 1: - raise DeprecationWarning( - "Passing DataSet is deprecated and will be disallowed in the future. Use DataArray instead." + warnings.warn( + "Passing DataSet is deprecated and will be disallowed in the future. Use DataArray instead.", + DeprecationWarning, + stacklevel=2, ) var_name = next(iter(proxy.data_vars)) _proxy = proxy[var_name] @@ -62,7 +70,7 @@ def disaggregate_polygon_to_raster( # make sure that crs of data and proxy match if _proxy.rio.crs != _data.crs: - print( + logger.info( f"CRS of `data` ({_data.crs}) does not match CRS of `proxy` ({_proxy.rio.crs}). Reprojecting CRS of `data` to match `proxy`'s CRS." ) _data = _data.to_crs(_proxy.rio.crs) @@ -86,7 +94,10 @@ def disaggregate_polygon_to_raster( id_nodata = len(value_lookup) - 1 # index of nodata in value_lookup belongs_to = get_belongs_to_matrix(_proxy, _data.geometry, nodata=id_nodata) if is_chunked_dask_array: - belongs_to = belongs_to.chunk(_proxy.chunks) + chunks = { + dim: chunk_size for dim, chunk_size in zip(_proxy.dims, _proxy.chunks) + } + belongs_to = belongs_to.chunk(chunks) belongs_to = belongs_to.data.astype("int32") if is_chunked_dask_array: @@ -111,7 +122,7 @@ def lookup_func(blk): ) if to_data_crs and _proxy.rio.crs != data.crs: - print(f"Reprojecting results to `data`'s CRS {data.crs}.") + logger.info(f"Reprojecting results to `data`'s CRS {data.crs}.") raster = raster.rio.reproject(data.crs) return raster @@ -151,44 +162,6 @@ def get_belongs_to_matrix( return xr.DataArray(arr, coords=raster.coords, dims=raster.dims) -def get_uniform_proxy( - polygons: gpd.GeoSeries, raster_resolution: tuple[int, int] -) -> xr.Dataset: - r""" - Get a uniform proxy which sums to one for each region. - - Parameters - ---------- - polygons : gpd.GeoSeries - Polygons to compute the proxy for. - raster_resolution : tuple[int, int] - Resolution of the desired raster proxy. - - Returns - ------- - xr.Dataset - Uniform proxy which sums to 1 in each region. - """ - # get spatial extent of spatial_units - x_min, y_min, x_max, y_max = polygons.total_bounds - - # define coords - x_coords = np.linspace(x_min, x_max, raster_resolution[0]) - y_coords = np.linspace(y_min, y_max, raster_resolution[1]) - - # create raster Dataset - uniform_proxy = xr.Dataset( - data_vars={}, coords={"x": ("x", x_coords), "y": ("y", y_coords)} - ) - - # TODO Set transform and crs - # uniform_proxy = uniform_proxy.rio.set_spatial_dims('x', 'y') - # uniform_proxy = uniform_proxy.rio.write_transform() - uniform_proxy = uniform_proxy.rio.set_crs(polygons.crs) - - return uniform_proxy - - def disaggregate_polygon_to_point( data: gpd.GeoDataFrame, column: str, @@ -217,7 +190,7 @@ def disaggregate_polygon_to_point( # compare crs. If not the same, project data to proxy's crs if not proxy.crs == _data.crs: - print( + logger.info( f"CRS of `proxy` ({proxy.crs}) does not match CRS of `data` ({_data.crs}). Reprojecting CRS of `data` to `proxy`'s CRS." ) _data = _data.to_crs(proxy.crs) @@ -255,7 +228,7 @@ def disaggregate_polygon_to_point( points = points[["geometry", "disaggregated"]] if to_data_crs: - print(f"Reprojecting results to `data`'s CRS {_data.crs}.") + logger.info(f"Reprojecting results to `data`'s CRS {_data.crs}.") points = points.to_crs(_data.crs) return points