From f4a6b80558c5009703148b0e14c4198239ed0b9c Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 15 Nov 2024 14:54:48 +0100 Subject: [PATCH 1/7] work around blocked HTTP requests from RTD to github (#93) * set custom user agent * [test-upstream] --- xdggs/tutorial.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xdggs/tutorial.py b/xdggs/tutorial.py index 7405f64..8d7807d 100644 --- a/xdggs/tutorial.py +++ b/xdggs/tutorial.py @@ -91,6 +91,7 @@ def open_dataset( -------- xarray.tutorial.open_dataset """ + import xdggs logger = pooch.get_logger() logger.setLevel("WARNING") @@ -109,8 +110,13 @@ def open_dataset( url = f"{base_url}/raw/{version}/{name}/{path.name}" + headers = {"User-Agent": f"xdggs/{xdggs.__version__}"} + # retrieve the file - filepath = pooch.retrieve(url=url, known_hash=None, path=cache_dir) + downloader = pooch.HTTPDownloader(headers=headers) + filepath = pooch.retrieve( + url=url, known_hash=None, path=cache_dir, downloader=downloader + ) ds = _open_dataset(filepath, engine=engine, **kws) if not cache: ds = ds.load() From 556a14aaeb176da901085d8ceefcec328b20a534 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 15 Nov 2024 14:59:54 +0100 Subject: [PATCH 2/7] citations file (#88) * use `cffconvert` to verify CITATION.cff files * initial version of `CITATION.cff` * add missing orcids * final orcid * correct the orcid format --- .pre-commit-config.yaml | 4 ++++ CITATION.cff | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 CITATION.cff diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 39eccab..edba990 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,6 +27,10 @@ repos: - id: blackdoc additional_dependencies: ["black==24.10.0"] - id: blackdoc-autoupdate-black + - repo: https://github.com/citation-file-format/cffconvert + rev: b6045d78aac9e02b039703b030588d54d53262ac + hooks: + - id: validate-cff - repo: https://github.com/kynan/nbstripout rev: 0.8.0 hooks: diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..c70de22 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,45 @@ +cff-version: 1.2.0 +title: xdggs +message: "If you use this software, please cite it as below." +type: software +authors: + - family-names: "Magin" + given-names: "Justus" + orcid: "https://orcid.org/0000-0002-4254-8002" + - family-names: "Bovy" + given-names: "Benoît" + orcid: "https://orcid.org/0009-0001-4011-3574" + - family-names: "Kmoch" + given-names: "Alexander" + orcid: "https://orcid.org/0000-0003-4386-4450" + - family-names: "Abernathey" + given-names: "Ryan" + orcid: "https://orcid.org/0000-0001-5999-4917" + - family-names: "Coca-Castro" + given-names: "Alejandro" + orcid: "https://orcid.org/0000-0002-9264-1539" + - family-names: "Strobl" + given-names: "Peter" + orcid: "https://orcid.org/0000-0003-2733-1822" + - family-names: "Fouilloux" + given-names: "Anne" + orcid: "https://orcid.org/0000-0002-1784-2920" + - family-names: "Loos" + given-names: "Daniel" + orcid: "https://orcid.org/0000-0002-4024-4443" + - family-names: "Chan" + given-names: "Wai Tik" + orcid: "https://orcid.org/0009-0005-3779-139X" + - family-names: "Delouis" + given-names: "Jean-Marc" + orcid: "https://orcid.org/0000-0002-0713-1658" + - family-names: "Odaka" + given-names: "Tina" + orcid: "https://orcid.org/0000-0002-1500-0156" +repository-code: "https://github.com/xarray-contrib/xdggs" +url: "https://xdggs.readthedocs.io" +keywords: + - xarray + - discrete global grid systems + - dggs +license: Apache-2.0 From b13251a20dfb61c077b74fb412b4dd8d1e942dec Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Mon, 18 Nov 2024 12:20:48 +0100 Subject: [PATCH 3/7] adapt to recent changes in `h3ronpy` (#94) * backwards-compatibility for recent `h3ronpy` changes * [test-upstream] --- xdggs/h3.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/xdggs/h3.py b/xdggs/h3.py index f9e5178..8a8fa4e 100644 --- a/xdggs/h3.py +++ b/xdggs/h3.py @@ -10,11 +10,19 @@ import numpy as np import xarray as xr -from h3ronpy.arrow.vector import ( - cells_to_coordinates, - cells_to_wkb_polygons, - coordinates_to_cells, -) + +try: + from h3ronpy.vector import ( + cells_to_coordinates, + cells_to_wkb_polygons, + coordinates_to_cells, + ) +except ImportError: + from h3ronpy.arrow.vector import ( + cells_to_coordinates, + cells_to_wkb_polygons, + coordinates_to_cells, + ) from xarray.indexes import PandasIndex from xdggs.grid import DGGSInfo, translate_parameters From 6d238cb2a0db5bf16421b7edf4d1eb5592097a5f Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Mon, 18 Nov 2024 13:39:01 +0100 Subject: [PATCH 4/7] lint / format hooks for `pyproject.toml` (#96) * add hooks to validate toml and `pyproject.toml` * remove the basic config file checkers * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add more specific version classifiers --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 13 +++++++-- pyproject.toml | 65 +++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index edba990..e62f892 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,13 +5,22 @@ repos: - id: trailing-whitespace - id: end-of-file-fixer - id: check-docstring-first - - id: check-yaml - - id: check-toml - repo: https://github.com/rbubley/mirrors-prettier rev: v3.3.3 hooks: - id: prettier args: [--cache-location=.prettier_cache/cache] + - repo: https://github.com/ComPWA/taplo-pre-commit + rev: v0.9.3 + hooks: + - id: taplo-format + args: [--option, array_auto_collapse=false] + - id: taplo-lint + args: [--no-schema] + - repo: https://github.com/abravalheri/validate-pyproject + rev: v0.23 + hooks: + - id: validate-pyproject - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.7.2 hooks: diff --git a/pyproject.toml b/pyproject.toml index c5ca828..391c861 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,30 +7,33 @@ fallback_version = "9999" [tool.setuptools.packages.find] include = [ - "xdggs", - "xdggs.*", + "xdggs", + "xdggs.*", ] [project] name = "xdggs" dynamic = ["version"] authors = [ - {name = "Benoît Bovy"}, - {name = "Justus Magin"}, + { name = "Benoît Bovy" }, + { name = "Justus Magin" }, ] maintainers = [ - {name = "xdggs contributors"}, + { name = "xdggs contributors" }, ] -license = {text = "Apache-2.0"} +license = { text = "Apache-2.0" } description = "Xarray extension for DGGS" keywords = ["DGGS", "xarray", "GIS"] readme = "Readme.md" classifiers = [ - "Intended Audience :: Science/Research", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Topic :: Scientific/Engineering :: GIS", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: GIS", ] requires-python = ">=3.10" dependencies = [ @@ -53,11 +56,11 @@ Repository = "https://github.com/xarray-contrib/xdggs" target-version = "py310" builtins = ["ellipsis"] exclude = [ - ".git", - ".eggs", - "build", - "dist", - "__pycache__", + ".git", + ".eggs", + "build", + "dist", + "__pycache__", ] line-length = 100 @@ -66,29 +69,29 @@ line-length = 100 # E501: line too long - let black worry about that # E731: do not assign a lambda expression, use a def ignore = [ - "E402", - "E501", - "E731", + "E402", + "E501", + "E731", ] select = [ - "F", # Pyflakes - "E", # Pycodestyle - "I", # isort - "UP", # Pyupgrade - "TID", # flake8-tidy-imports - "W", + "F", # Pyflakes + "E", # Pycodestyle + "I", # isort + "UP", # Pyupgrade + "TID", # flake8-tidy-imports + "W", ] extend-safe-fixes = [ - "TID252", # absolute imports + "TID252", # absolute imports ] fixable = ["I", "TID252"] [tool.ruff.lint.isort] known-first-party = ["xdggs"] -known-third-party=[ - "xarray", - "healpy", - "h3ronpy", +known-third-party = [ + "xarray", + "healpy", + "h3ronpy", ] [tool.ruff.lint.flake8-tidy-imports] @@ -105,5 +108,5 @@ exclude_lines = ["pragma: no cover", "if TYPE_CHECKING"] [tool.pytest.ini_options] filterwarnings = [ - "error:::xdggs.*", + "error:::xdggs.*", ] From d540d51605f8a98830bc0f9bff244b5a9e08dc03 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Mon, 18 Nov 2024 14:55:33 +0100 Subject: [PATCH 5/7] use bibtex for publications (#89) * include the tutorials directly in the top level * move api reference and publications to the reference * delete the outdated tutorial index * `pre-commit` hook to format bibtex * ignore all `generated` dirs in `docs` * ignore bibtex files * remove `tidybib` again, it clashes with other hooks * configure and use `sphinxcontrib-bibtex` * add `sphinxcontrib-bibtex` to the docs env * move the api reference back to the main directory * add back the accidentally deleted api files * add `bibtex-tidy` to normalize bibtex files * work around limitations of bibtex-tidy * don't drop all caps * reformat the bibtex file * new entry for the egu presentation * remove the overrides to support running on `pre-commit` * confine the `bibtex-tidy` hook to manual It currently requires `node` to be installed, which we can't really require. --- .gitignore | 6 ++++- .pre-commit-config.yaml | 12 ++++++++++ ci/docs.yml | 1 + docs/conf.py | 5 ++++ docs/index.md | 22 +++++++++--------- docs/reference_guide/publications.bib | 33 +++++++++++++++++++++++++++ docs/reference_guide/publications.md | 9 ++++++++ docs/tutorials/index.md | 13 ----------- docs/user_guide/publications.md | 3 --- 9 files changed, 76 insertions(+), 28 deletions(-) create mode 100644 docs/reference_guide/publications.bib create mode 100644 docs/reference_guide/publications.md delete mode 100644 docs/tutorials/index.md delete mode 100644 docs/user_guide/publications.md diff --git a/.gitignore b/.gitignore index 259be44..3e1f4e3 100644 --- a/.gitignore +++ b/.gitignore @@ -70,7 +70,7 @@ instance/ # Sphinx documentation docs/_build/ -docs/generated/ +docs/**/generated/ # PyBuilder .pybuilder/ @@ -163,3 +163,7 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# bibtex +.auctex-auto +*.bib.untidy diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e62f892..8173cf3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,6 +45,18 @@ repos: hooks: - id: nbstripout args: [--extra-keys=metadata.kernelspec metadata.langauge_info.version] + - repo: https://github.com/FlamingTempura/bibtex-tidy + rev: v1.14.0 + hooks: + - id: bibtex-tidy + stages: [manual] + args: + - "--modify" + - "--blank-lines" + - "--sort=-year,name" + - "--duplicates" + - "--escape" + - "--trailing-commas" ci: autofix_prs: true diff --git a/ci/docs.yml b/ci/docs.yml index 81d43cc..760ee31 100644 --- a/ci/docs.yml +++ b/ci/docs.yml @@ -10,6 +10,7 @@ dependencies: - sphinx-copybutton - sphinx-design - sphinx-inline-tabs + - sphinxcontrib-bibtex - xarray - healpy - h5netcdf diff --git a/docs/conf.py b/docs/conf.py index c57401a..c4f9b13 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,7 @@ "IPython.sphinxext.ipython_console_highlighting", "sphinx_autosummary_accessors", "myst_nb", + "sphinxcontrib.bibtex", ] extlinks = { @@ -103,3 +104,7 @@ nb_execution_timeout = -1 nb_execution_cache_path = "_build/myst-nb" + +# -- sphinxcontrib-bibtex ---------------------------------------------------- + +bibtex_bibfiles = ["reference_guide/publications.bib"] diff --git a/docs/index.md b/docs/index.md index 4b5cdf0..47b0aa1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,28 +14,28 @@ maxdepth: 3 caption: Tutorials hidden: true --- - -Tutorials +tutorials/h3 +tutorials/healpix ``` -```{toctree} ---- -maxdepth: 3 -caption: User guide -hidden: true ---- -Publications -``` + + + + + + + ```{toctree} --- maxdepth: 3 -caption: Technical information +caption: Reference guide hidden: true --- Changelog API Reference +Publications ``` # Welcome to `xdggs` diff --git a/docs/reference_guide/publications.bib b/docs/reference_guide/publications.bib new file mode 100644 index 0000000..9a6494f --- /dev/null +++ b/docs/reference_guide/publications.bib @@ -0,0 +1,33 @@ +@misc{magin_2024_13934967, + author = {Magin, Justus and Bovy, Benoit and Delouis, Jean-Marc and Fouilloux, Anne and Coca-Castro, Alejandro and Abernathey, Ryan and Strobl, Peter and Kmoch, Alexander and Odaka, Tina Erica}, + title = "{Advancing Geospatial Data Analysis with XDGGS}", + year = 2024, + month = oct, + doi = {10.5281/zenodo.13934967}, + publisher = {Zenodo}, + url = {https://doi.org/10.5281/zenodo.13934967}, + version = {1.0}, +} + +@article{isprs-archives-XLVIII-4-W12-2024-75-2024, + author = {Kmoch, A. and Bovy, B. and Magin, J. and Abernathey, R. and Coca-Castro, A. and Strobl, P. and Fouilloux, A. and Loos, D. and Uuemaa, E. and Chan, W. T. and Delouis, J.-M. and Odaka, T.}, + title = "{XDGGS: A community-developed Xarray package to support planetary DGGS data cube computations}", + journal = {The International Archives of the Photogrammetry, Remote Sensing and Spatial Information Sciences}, + year = 2024, + volume = {XLVIII-4/W12-2024}, + pages = {75--80}, + doi = {10.5194/isprs-archives-XLVIII-4-W12-2024-75-2024}, + url = {https://isprs-archives.copernicus.org/articles/XLVIII-4-W12-2024/75/2024/}, +} + +@inproceedings{kmoch2024, + title = {{{XDGGS}}: {{Xarray Extension}} for {{Discrete Global Grid Systems}} ({{DGGS}})}, + shorttitle = {{XDGGS}}, + author = {Kmoch, Alexander and Bovy, Beno{\^i}t and Magin, Justus and Abernathey, Ryan and Strobl, Peter and {Coca-Castro}, Alejandro and Fouilloux, Anne and Loos, Daniel and Odaka, Tina}, + year = {2024}, + month = Apr, + booktitle = {{{EGU General Assembly}} 2024}, + address = {Vienna, Austria, 14-19 Apr 2024}, + doi = {10.5194/egusphere-egu24-15416}, + urldate = {2024-11-18}, +} diff --git a/docs/reference_guide/publications.md b/docs/reference_guide/publications.md new file mode 100644 index 0000000..1e6301d --- /dev/null +++ b/docs/reference_guide/publications.md @@ -0,0 +1,9 @@ +# Publications mentioning `xdggs` + +```{bibliography} publications.bib +--- +all: true +list: bullet +style: alpha +--- +``` diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md deleted file mode 100644 index c243fb3..0000000 --- a/docs/tutorials/index.md +++ /dev/null @@ -1,13 +0,0 @@ -# Example Notebooks - -You will find here simple examples and tutorials. - -```{toctree} ---- -maxdepth: 1 -caption: Tutorials ---- - -h3 -healpix -``` diff --git a/docs/user_guide/publications.md b/docs/user_guide/publications.md deleted file mode 100644 index de47e8d..0000000 --- a/docs/user_guide/publications.md +++ /dev/null @@ -1,3 +0,0 @@ -# Publications mentioning `xdggs` - -- [DestinE User Meeting 2024](https://doi.org/10.5281/zenodo.13934967) From 61c5ac2d6360053f852b9bc6fbe9f171a9086b16 Mon Sep 17 00:00:00 2001 From: Lionel Zawadzki <74003469+zawadzl@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:41:55 +0100 Subject: [PATCH 6/7] acknowledge the funding (#95) * Update README.md with CNES acknowledgment * remove inspiration message from the acknowledgements * acknowledge the funding that allowed the creation of xdggs --------- Co-authored-by: Justus Magin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11bc14c..f8dfc35 100644 --- a/README.md +++ b/README.md @@ -83,4 +83,4 @@ We welcome contributions to `xdggs`! Please follow these steps to get involved: ## Acknowledgments -This project was inspired by the increasing need for scalable geospatial data analysis using DGGS and is built upon the robust ecosystem of Xarray. +This project was initiated using funding from CNES (PANGEO IAOCEA, contract R&T R-S23/DU-0002-025-01) and the European Union (ERC, WaterSmartLand, 101125476, Interreg-BSR, HyTruck, #C031). From ce81a17aca28bac261b06fd76c93e71044c95d69 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 22 Nov 2024 13:47:45 +0100 Subject: [PATCH 7/7] replace `healpy` with `cdshealpix` (#92) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * start replacing `healpy` with `cdshealpix` * work around a dtype casting bug in cdshealpix * reorder the cell vertices (`cdshealpix` starts with a different pixel than `healpy` – otherwise they're the same) * depend on `cdshealpix` instead of `healpy` * add `cdshealpix-python` to intersphinx * also install `cdshealpix` instead of `healpy` in the upstream-dev ci * change the backend library in the docstring of `from_dict` * test with more dtypes * run CI on windows * don't install `conda` since we don't need it * install `cdshealpix` from PyPI * only enforce colors for `pytest` * override `FORCE_COLOR` for `setup-micromamba` specifically * pin `micromamba` instead * use `assert_allclose` to compare --- .github/workflows/ci.yml | 4 +-- ci/docs.yml | 2 +- ci/environment.yml | 2 +- ci/install-upstream-wheels.sh | 24 +++--------------- docs/conf.py | 1 + docs/tutorials/healpix.ipynb | 24 +++++++++++++----- environment.yml | 2 +- pyproject.toml | 5 ++-- xdggs/healpix.py | 48 ++++++++++++++++++++++++++++------- xdggs/tests/test_healpix.py | 34 ++++++++++++------------- 10 files changed, 85 insertions(+), 61 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6521f2..48b682e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: fail-fast: false matrix: - os: ["ubuntu-latest", "macos-latest"] + os: ["ubuntu-latest", "macos-latest", "windows-latest"] python-version: ["3.10", "3.11", "3.12"] steps: @@ -61,13 +61,13 @@ jobs: - name: Setup micromamba uses: mamba-org/setup-micromamba@v2 with: + micromamba-version: "1.5.10-0" environment-file: ${{ env.CONDA_ENV_FILE }} environment-name: xdggs-tests cache-environment: true cache-environment-key: "${{runner.os}}-${{runner.arch}}-py${{matrix.python-version}}-${{env.TODAY}}-${{hashFiles(env.CONDA_ENV_FILE)}}" create-args: >- python=${{matrix.python-version}} - conda - name: Install xdggs run: | diff --git a/ci/docs.yml b/ci/docs.yml index 760ee31..1a9167f 100644 --- a/ci/docs.yml +++ b/ci/docs.yml @@ -12,7 +12,6 @@ dependencies: - sphinx-inline-tabs - sphinxcontrib-bibtex - xarray - - healpy - h5netcdf - netcdf4 - pooch @@ -28,4 +27,5 @@ dependencies: - pip - pip: - h3ronpy + - cdshealpix - -e .. diff --git a/ci/environment.yml b/ci/environment.yml index df64888..b5f2eb2 100644 --- a/ci/environment.yml +++ b/ci/environment.yml @@ -2,7 +2,6 @@ channels: - conda-forge dependencies: - xarray - - healpy - h5netcdf - netcdf4 - pooch @@ -18,3 +17,4 @@ dependencies: - pip - pip: - h3ronpy + - cdshealpix diff --git a/ci/install-upstream-wheels.sh b/ci/install-upstream-wheels.sh index 1b39f4d..70a4cb4 100644 --- a/ci/install-upstream-wheels.sh +++ b/ci/install-upstream-wheels.sh @@ -10,7 +10,7 @@ fi $conda remove -y --force \ xarray \ pandas \ - healpy + cdshealpix python -m pip uninstall -y h3ronpy # install from scientific-python wheels @@ -36,23 +36,5 @@ python -m pip install \ python -m pip install --no-deps --upgrade \ git+https://github.com/Unidata/cftime \ git+https://github.com/astropy/astropy \ - "git+https://github.com/nmandery/h3ronpy#subdirectory=h3ronpy" - -# install healpy from github -# need to run `auditwheel` to include the shared libs -python -m pip install auditwheel - -# build and repair the wheel -# - manual clone -mkdir deps -git clone --filter=blob:none --quiet https://github.com/healpy/healpy deps/healpy -pushd deps/healpy -git submodule update --init --recursive -q -# - build and repair the wheel -mkdir -p built_wheel repaired_wheel -python -m pip wheel --no-deps . --wheel-dir built_wheel -auditwheel repair --plat linux_x86_64 -w repaired_wheel built_wheel/healpy-*.whl -# - install the repaired wheel -python -m pip install --upgrade --no-deps repaired_wheel/healpy-*.whl -# - clean up -popd; rm -rf deps + "git+https://github.com/nmandery/h3ronpy#subdirectory=h3ronpy" \ + git+https://github.com/cds-astro/cds-healpix-python diff --git a/docs/conf.py b/docs/conf.py index c4f9b13..dbde2f3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,6 +97,7 @@ "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None), "lonboard": ("https://developmentseed.org/lonboard/latest", None), "healpy": ("https://healpy.readthedocs.io/en/latest", None), + "cdshealpix-python": ("https://cds-astro.github.io/cds-healpix-python", None), "shapely": ("https://shapely.readthedocs.io/en/stable", None), } diff --git a/docs/tutorials/healpix.ipynb b/docs/tutorials/healpix.ipynb index 67e26e4..dde5a15 100644 --- a/docs/tutorials/healpix.ipynb +++ b/docs/tutorials/healpix.ipynb @@ -152,19 +152,29 @@ "derived_ds" ] }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "```{note}\n", + "We need to use {py:func}`xarray.testing.assert_allclose` to compare cell centers because the cell center coordinates were computed using a [different library](https://github.com/healpy/healpy) with a slightly different implementation, resulting in small floating point differences.\n", + "```" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "11", + "id": "12", "metadata": {}, "outputs": [], "source": [ - "xr.testing.assert_equal(derived_ds, original_ds)" + "xr.testing.assert_allclose(derived_ds, original_ds)" ] }, { "cell_type": "markdown", - "id": "12", + "id": "13", "metadata": {}, "source": [ "### Cell boundary polygons\n", @@ -175,7 +185,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -185,7 +195,7 @@ }, { "cell_type": "markdown", - "id": "14", + "id": "15", "metadata": {}, "source": [ "## Plotting\n", @@ -200,7 +210,7 @@ { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -219,7 +229,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.7" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/environment.yml b/environment.yml index 638ace6..ffd14bd 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,7 @@ channels: - conda-forge dependencies: - xarray - - healpy + - cdshealpix - ruff - pytest - h5netcdf diff --git a/pyproject.toml b/pyproject.toml index 391c861..30ed6eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ classifiers = [ requires-python = ">=3.10" dependencies = [ "xarray", - "healpy", + "cdshealpix", "h3ronpy", "typing-extensions", "lonboard>=0.9.3", @@ -90,7 +90,8 @@ fixable = ["I", "TID252"] known-first-party = ["xdggs"] known-third-party = [ "xarray", - "healpy", + "cdshealpix", + "astropy", "h3ronpy", ] diff --git a/xdggs/healpix.py b/xdggs/healpix.py index ab1db0f..089ce84 100644 --- a/xdggs/healpix.py +++ b/xdggs/healpix.py @@ -8,7 +8,8 @@ except ImportError: # pragma: no cover from typing_extensions import Self -import healpy +import cdshealpix.nested +import cdshealpix.ring import numpy as np import xarray as xr from xarray.indexes import PandasIndex @@ -105,7 +106,7 @@ class HealpixInfo(DGGSInfo): .. warning:: Note that ``"unique"`` is currently not supported as the underlying library - (:doc:`healpy `) does not support it. + (:doc:`cdshealpix `) does not support it. """ level: int @@ -210,9 +211,17 @@ def cell_ids2geographic(self, cell_ids): lat : array-like The latitude coordinate values of the grid cells in degree """ - lon, lat = healpy.pix2ang(self.nside, cell_ids, nest=self.nest, lonlat=True) + converters = { + "nested": cdshealpix.nested.healpix_to_lonlat, + "ring": lambda cell_ids, level: cdshealpix.ring.healpix_to_lonlat( + cell_ids, nside=2**level + ), + } + converter = converters[self.indexing_scheme] + + lon, lat = converter(cell_ids, self.level) - return lon, lat + return np.asarray(lon.to("degree")), np.asarray(lat.to("degree")) def geographic2cell_ids(self, lon, lat): """ @@ -233,7 +242,20 @@ def geographic2cell_ids(self, lon, lat): cell_ids : array-like Array-like containing the cell ids. """ - return healpy.ang2pix(self.nside, lon, lat, lonlat=True, nest=self.nest) + from astropy.coordinates import Latitude, Longitude + + converters = { + "nested": cdshealpix.nested.lonlat_to_healpix, + "ring": lambda lon, lat, level: cdshealpix.ring.lonlat_to_healpix( + lon, lat, nside=2**level + ), + } + converter = converters[self.indexing_scheme] + + longitude = Longitude(lon, unit="degree") + latitude = Latitude(lat, unit="degree") + + return converter(longitude, latitude, self.level) def cell_boundaries(self, cell_ids: Any, backend="shapely") -> np.ndarray: """ @@ -255,11 +277,19 @@ def cell_boundaries(self, cell_ids: Any, backend="shapely") -> np.ndarray: - ``"shapely"``: return a array of :py:class:`shapely.Polygon` objects - ``"geoarrow"``: return a ``geoarrow`` array """ - boundary_vectors = healpy.boundaries( - self.nside, cell_ids, step=1, nest=self.nest - ) + converters = { + "nested": cdshealpix.nested.vertices, + "ring": lambda cell_ids, level, **kwargs: cdshealpix.ring.vertices( + cell_ids, nside=2**level, **kwargs + ), + } + converter = converters[self.indexing_scheme] + + lon_, lat_ = converter(cell_ids, self.level, step=1) + + lon = np.asarray(lon_.to("degree")) + lat = np.asarray(lat_.to("degree")) - lon, lat = healpy.vec2ang(np.moveaxis(boundary_vectors, 1, -1), lonlat=True) lon_reshaped = np.reshape(lon, (-1, 4)) lat_reshaped = np.reshape(lat, (-1, 4)) diff --git a/xdggs/tests/test_healpix.py b/xdggs/tests/test_healpix.py index 0e8d82c..c2ea54a 100644 --- a/xdggs/tests/test_healpix.py +++ b/xdggs/tests/test_healpix.py @@ -55,8 +55,7 @@ def grid_mappings(cls): def cell_ids(max_value=None, dtypes=None): if dtypes is None: - # healpy can't deal with `uint32` or less (it segfaults occasionally) - dtypes = st.sampled_from(["uint64"]) + dtypes = st.sampled_from(["int32", "int64", "uint32", "uint64"]) shapes = npst.array_shapes(min_dims=1, max_dims=1) return npst.arrays( @@ -89,9 +88,7 @@ def grid_and_cell_ids( cell_levels = st.shared(levels, key="common-levels") grid_levels = st.shared(levels, key="common-levels") cell_ids_ = cell_levels.flatmap( - lambda level: cls.cell_ids( - max_value=12 * 2 ** (level * 2) - 1, dtypes=dtypes - ) + lambda level: cls.cell_ids(max_value=12 * 4**level - 1, dtypes=dtypes) ) grids_ = cls.grids( levels=grid_levels, @@ -222,10 +219,10 @@ def test_roundtrip(self, level, indexing_scheme): np.array([2]), np.array( [ - [-135.0, 90.0], - [-180.0, 41.8103149], [-135.0, 0.0], [-90.0, 41.8103149], + [-135.0, 90.0], + [-180.0, 41.8103149], ] ), ), @@ -235,16 +232,16 @@ def test_roundtrip(self, level, indexing_scheme): np.array( [ [ - [0.0, 66.44353569], - [0.0, 54.3409123], [22.5, 41.8103149], [30.0, 54.3409123], + [0.0, 66.44353569], + [0.0, 54.3409123], ], [ - [-45.0, 41.8103149], - [-56.25, 30.0], [-45.0, 19.47122063], [-33.75, 30.0], + [-45.0, 41.8103149], + [-56.25, 30.0], ], ] ), @@ -255,16 +252,16 @@ def test_roundtrip(self, level, indexing_scheme): np.array( [ [ - [-5.625, 4.78019185], - [-11.25, 0.0], [-5.625, -4.78019185], [0.0, 0.0], + [-5.625, 4.78019185], + [-11.25, 0.0], ], [ - [73.125, 35.68533471], - [67.5, 30.0], [73.125, 24.62431835], [78.75, 30.0], + [73.125, 35.68533471], + [67.5, 30.0], ], ] ), @@ -274,10 +271,10 @@ def test_roundtrip(self, level, indexing_scheme): np.array([79]), np.array( [ - [0.0, 41.8103149], - [-11.25, 30], [0.0, 19.47122063], [11.25, 30], + [0.0, 41.8103149], + [-11.25, 30], ] ), ), @@ -300,6 +297,9 @@ def test_cell_boundaries(self, params, cell_ids, backend, expected_coords): @given( *strategies.grid_and_cell_ids( + # a dtype casting bug in the valid range check of `cdshealpix` + # causes this test to fail for large levels + levels=st.integers(min_value=0, max_value=10), indexing_schemes=st.sampled_from(["nested", "ring"]), dtypes=st.sampled_from(["int64"]), )