Showing preview only (2,640K chars total). Download the full file or copy to clipboard to get everything.
Repository: pangeo-data/xESMF
Branch: master
Commit: 43b6a456a1f9
Files: 58
Total size: 2.5 MB
Directory structure:
gitextract_0jcmuyrd/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yaml
│ ├── linting.yaml
│ └── pypi.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .prettierrc.toml
├── CHANGES.rst
├── LICENSE
├── MANIFEST.in
├── README.rst
├── binder/
│ └── environment.yml
├── ci/
│ ├── doc.yml
│ ├── environment-upstream-dev.yml
│ └── environment.yml
├── codecov.yml
├── doc/
│ ├── Makefile
│ ├── changes.rst
│ ├── conf.py
│ ├── index.rst
│ ├── installation.rst
│ ├── internal_api.rst
│ ├── large_problems_on_HPC.rst
│ ├── limitations.rst
│ ├── make.bat
│ ├── notebooks/
│ │ ├── Backend.ipynb
│ │ ├── Compare_algorithms.ipynb
│ │ ├── Curvilinear_grid.ipynb
│ │ ├── Dask.ipynb
│ │ ├── Dataset.ipynb
│ │ ├── Masking.ipynb
│ │ ├── Pure_numpy.ipynb
│ │ ├── Rectilinear_grid.ipynb
│ │ ├── Reuse_regridder.ipynb
│ │ ├── Spatial_Averaging.ipynb
│ │ └── Using_LocStream.ipynb
│ ├── other_tools.rst
│ ├── releases.rst
│ ├── requirements.txt
│ ├── user_api.rst
│ └── why.rst
├── pyproject.toml
├── readthedocs.yml
├── requirements.txt
├── setup.cfg
└── xesmf/
├── __init__.py
├── backend.py
├── data.py
├── frontend.py
├── smm.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_backend.py
│ ├── test_frontend.py
│ ├── test_oceanmodels.py
│ ├── test_smm.py
│ └── test_util.py
└── util.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
# - package-ecosystem: pip
# directory: "/"
# schedule:
# interval: daily
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates once a week
interval: "weekly"
================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI
on:
push:
branches:
- master
pull_request:
branches:
- "*"
schedule:
- cron: "0 0 * * *" # Daily “At 00:00”
workflow_dispatch: # allows you to trigger manually
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
strategy:
fail-fast: false
matrix:
include:
# Warning: Unless in quotations, numbers below are read as floats. 3.10 < 3.2
- python-version: "3.11"
esmf-version: 8.4
- python-version: "3.12"
esmf-version: 8.6
- python-version: "3.13"
esmf-version: 8.8
- python-version: "3.14"
esmf-version: 8.9
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- name: Checkout source
uses: actions/checkout@v6
- name: Create conda environment
uses: mamba-org/setup-micromamba@v3
with:
cache-downloads: true
micromamba-version: "latest"
environment-file: ci/environment.yml
create-args: >-
python=${{ matrix.python-version }}
esmpy=${{ matrix.esmf-version }}
- name: Fix env for esmpy 8.4
run: |
if [ "${{ matrix.esmf-version }}" == "8.4" ]; then
conda install "importlib-metadata<8.0.0"
fi
- name: Install Xesmf (editable)
run: |
python -m pip install --no-deps -e .
- name: Conda list information
run: |
conda env list
conda list
- name: Run tests
run: |
python -m pytest --cov=./ --cov-report=xml --verbose
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6.0.0
with:
files: ./coverage.xml
fail_ci_if_error: false
upstream-dev:
name: upstream-dev
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.13.1
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v6
- name: Create conda environment
uses: mamba-org/setup-micromamba@v3
with:
cache-downloads: true
micromamba-version: "latest"
environment-file: ci/environment-upstream-dev.yml
- name: Install Xesmf (editable)
run: |
python -m pip install -e .
- name: Conda list information
run: |
conda env list
conda list
- name: Run tests
run: |
python -m pytest --cov=./ --cov-report=xml --verbose
================================================
FILE: .github/workflows/linting.yaml
================================================
name: linting
on:
push:
branches:
- master
pull_request:
branches: "*"
jobs:
linting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: pre-commit/action@v3.0.1
================================================
FILE: .github/workflows/pypi.yaml
================================================
name: Publish to PyPI
on:
pull_request:
push:
branches:
- master
release:
types:
- published
defaults:
run:
shell: bash
jobs:
packages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Get tags
run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- name: Install build tools
run: |
python -m pip install --upgrade build
- name: Build binary wheel
run: python -m build --sdist --wheel . --outdir dist
- name: CheckFiles
run: |
ls dist
python -m pip install --upgrade check-manifest
check-manifest --verbose
- name: Test wheels
run: |
# We cannot run this step b/c esmpy is not available on PyPI
# cd dist && python -m pip install *.whl && cd ..
python -m pip install --upgrade build twine
python -m twine check dist/*
- name: Publish a Python distribution to PyPI
if: success() && github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
_version.py
# Sphinx documentation
docs/_build/
doc/_build/
# notebook
.ipynb_checkpoints
# OS-generated
.DS_Store
# NetCDF files
*.nc
*.nc4
# ESMPy log files
PET0.ESMF_LogFile
# Unit test / coverage reports
.cache
.coverage
coverage.xml
dask-worker-space/
================================================
FILE: .pre-commit-config.yaml
================================================
default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-docstring-first
- id: check-json
- id: check-yaml
- id: double-quote-string-fixer
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.3.1
hooks:
- id: black
- repo: https://github.com/keewis/blackdoc
rev: v0.4.6
hooks:
- id: blackdoc
- repo: https://github.com/PyCQA/flake8
rev: 7.3.0
hooks:
- id: flake8
- repo: https://github.com/PyCQA/isort
rev: 8.0.1
hooks:
- id: isort
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
hooks:
- id: prettier
- repo: https://github.com/deathbeds/prenotebook
rev: f5bdb72a400f1a56fe88109936c83aa12cc349fa
hooks:
- id: prenotebook
args:
[
"--keep-output",
"--keep-metadata",
"--keep-execution-count",
"--keep-empty",
]
- repo: https://github.com/tox-dev/pyproject-fmt
rev: v2.21.0
hooks:
- id: pyproject-fmt
ci:
autofix_commit_msg: |
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
autofix_prs: true
autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
autoupdate_schedule: monthly
skip: []
submodules: false
================================================
FILE: .prettierrc.toml
================================================
tabWidth = 2
semi = false
singleQuote = true
================================================
FILE: CHANGES.rst
================================================
What's new
==========
0.9.2 (2025-11-27)
------------------
This release drops support for Python < 3.11. xESMF aims to preserve support for older python and ESMF version as long as possible with its reduced maintaining team. The most recent windows release of ESMF is currently 8.4.2 and new versions of xESMF will support it as long as it is not updated. All fixes in :pull:`463`, by `Pascal Bourgault <https://github.com/aulemahal>`_.
* Rewrote ``xe.smm.gen_mask_from_weights`` to remove scipy-dependent code.
* Fix the CI reenable testing with previous python versions.
* Avoid a ``SpatialAverager`` bug that happens when polygon segments have a length of exactly 1 on ESMF 8.4.2. The bug is not actually fixed in xESMF, but "segmentizing" the polygons with 0.99 seems to fix the issue.
0.9.1 (2025-11-25)
------------------
* Rewrote ``xe.smm.add_nans_to_weight`` (called when ``unmapped_to_nan`` is True)to remove scipy-dependent code, which also resulted in a significant (>=4x) speedup of that step (:pull:`461`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Fix some name collision issues in the parallel regridder initialisation (:pull:`461`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.9.0 (2025-11-21)
------------------
* Added ``Regridder`` option ``post_mask_source`` to mask contributions of specified source grid cells, with a special setting for masking domain edge cells to avoid extrapolation with ``nearest_s2d`` when remapping to a larger domain (``post_mask_source = 'domain_edge'``, :pull:`444`). By `Martin Schupfner <https://github.com/sol1105>`_.
* Added support for target masks when regridding ``LocStream`` to ``Grid`` with ``nearest_s2d`` (:pull:`445`). By `Martin Schupfner <https://github.com/sol1105>`_.
* ``xesmf.util.cf_grid_2d`` returns bounds as coordinates, as ``grid_2d`` does and as usually expected. (:pull:`453`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Accept masks in "X, Y" order (:issue:`447`, :pull:`456`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Correctly use arguments ``input_dims`` and ``output_dims`` in ``Regridder`` when grids are defined as dictionaries of numpy arrays (:issue:`362`, :pull:`455`). By `Aaron G Meyer <https://github.com/agmeyer4>`_.
0.8.10 (2025-04-29)
-------------------
* Fix issue introduced by :pull:`418` for passing grids as dictionaries. (:issue:`428`, :pull:`429`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.9 (2025-04-15)
------------------
* Destroy grids explicitly once weights are computed. Do not store them in `grid_in` and `grid_out` attributes. This fixes segmentation faults introduced by the memory fix of last version. By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Do not add scalar coordinates of the target grid to the regridded output (:issue:`417`, :pull:`418`). `xe.Regridder.out_coords` is now a dataset instead of a dictionary. By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.8 (2024-11-01)
------------------
* Fix ESMpy memory issues by explictly freeing the Grid memory upon garbage collection of ``Regridder`` objects. By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Address deprecation for xarray 2024.10 in the parallel weight generation. By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Address an upcoming change in sparse 0.16 where COO fill values will distinguish between 0.0 and -0.0. This issue would affect spatial averaging over polygons with holes. By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.7 (2024-07-16)
------------------
* Cast grid sizes to python's int (another Numpy 2.0 fix). (:pull:`377`) By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.6 (2024-06-26)
------------------
* New ``xe.util.cell_area`` utility to compute the cell area using ESMF's internal mechanism. (:pull:`372`, :issue:`369`) By `Jiawei Zhuang <https://github.com/JiaweiZhuang>`_ and `Pascal Bourgault <https://github.com/aulemahal>`_.
* Compatibility with Numpy 2.0 (NaN vs nan) (:pull:`373`) By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.5 (2024-04-11)
------------------
* Reverted to the chunking behaviour of xESMF 0.7 for cases where the spatial dimensions are not chunked on the source data. (:pull:`348`) By `Pascal Bourgault <https://github.com/aulemahal>`_.
0.8.4 (2024-02-26)
------------------
* Fix regression from :pull:`332` that made ``Regridder`` fail with rectilinear datasets and ``parallel=True``. (:issue:`343`, :pull:`344`).
* Allow Python 3.12 (and higher) again. (:pull:`345`).
0.8.3 (2024-02-20)
------------------
* Remove usage of private method of xarray that was removed in its 2024.02.0 version (:issue:`338`, :issue:`340`) By `Pascal Bourgault <https://github.com/aulemahal>`_.
Internal changes
~~~~~~~~~~~~~~~~
* Test against ESMF 8.6
0.8.2 (2023-09-18)
------------------
Bug fixes
~~~~~~~~~
* Raise a meaningful error messages when the output grid has no chunks with `parallel=True` (:issue:`299`, :pull:`304`). By `Pascal Bourgault <https://github.com/aulemahal>`_.
* Correct guess of output chunks for ``SpatialAverager``.
0.8.1 (2023-09-05)
------------------
Bug fixes
~~~~~~~~~
* Change import to support shapely 1 and 2.
0.8.0 (2023-09-01)
------------------
This release of xESMF improves support for parallelization with dask: weights can now be computed in parallel, and those weights can be applied over chunks spanning the horizontal grid dimensions. Previously, computing weights in parallel was only possible using MPI, and datasets could only be chunked over non-spatial dimensions.
These new features are the outcome of `Charles Gauthier <https://github.com/charlesgauthier-udm>`_'s internship at `Ouranos <https://www.ouranos.ca/>`_ during the summer of 2023. Thanks to Charles for his hard work and sharp analysis, which led to a permanent position at Ouranos!
New features
~~~~~~~~~~~~
* Added a check in SpatialAverager that warns user if they are using polygons with long segments that could cause errors (:pull:`293`). By `Charles Gauthier <https://github.com/charlesgauthier-udm>`_
* Add an option (``parallel``) to generate regridding weights in parallel using dask (:pull:`290`). By `Charles Gauthier <https://github.com/charlesgauthier-udm>`_
* Add the ability to apply weights using dask on chunked horizontal/core dimensions. The ``output_chunks`` argument to the `Regridder` class
allows setting the chunk sizes of the output data (:pull:`280`). By `Charles Gauthier <https://github.com/charlesgauthier-udm>`_
* Added a `w` property to the `Regridder` and `SpatialAverager` classes, returning the weights reshaped according to
the input and output grid dimensions. This is mostly intended for debugging and visualisation purposes (:pull:`276`). By `David Huard <https://github.com/huard>`_
Documentation
~~~~~~~~~~~~~
* Move URLs from earthsystemcog.org to earthsystemmodeling.org (:pull:`292`).
Internal changes
~~~~~~~~~~~~~~~~
* Remove Python 3.7 from the project classifiers
* Build docs using Python 3.9
0.7.1 (2023-04-03)
------------------
Bug fixes
~~~~~~~~~
* Fix ``Mesh.from_polygons`` and unpin Shapely to add support for Shapely 2.0 (:pull:`219`). By `Pascal Bourgault <https://github.com/aulemahal>`_
* Implement workaround for setup conda problem (:pull:`229`). By `Raphael Dussin <https://github.com/raphaeldussin>`_
* Update CI and doc - fix for DataArrays (:pull:`230`). By `Pascal Bourgault <https://github.com/aulemahal>`_
* Fix ci/cd badge for build status (:pull:`231`). By `Pierre Manchon <https://github.com/pierre-manchon>`_
* Update CI for Micromamba environments (:pull:`233`). By `Trevor James Smith <https://github.com/Zeitsperre>`_
* Fix error in test with Shapely 2.0 (:pull:`251`). By `David Huard <https://github.com/huard>`_
New features
~~~~~~~~~~~~
* Add util to build tripolar grid (:pull:`228`). By `Raphael Dussin <https://github.com/raphaeldussin>`_
Documentation
~~~~~~~~~~~~~
* Document installation options for ESMpy (:pull:`241`). By `Matthew Plough <https://github.com/mplough-kobold>`_
Internal changes
~~~~~~~~~~~~~~~~
* Modernize the package configuration / publish to PyPI (:pull:`248`). By `Filipe Fernandes <https://github.com/ocefpaf>`_
0.7.0 (2022-12-16)
------------------
Bug fixes
~~~~~~~~~
- Fix bug in `util.grid_global` where grid centers could go beyond 180 degrees (:issue:`181`). By `David Huard <https://github.com/huard>`_
New features
~~~~~~~~~~~~
- Support both [-180, 180] and [0, 360] conventions in `grid_global` (:issue:`149`). By `David Huard <https://github.com/huard>`_
Documentation
~~~~~~~~~~~~~
- Fix API doc build (:pull:`194`). By `David Huard <https://github.com/huard>`_
- Include `conservative_normed` into the notebook comparing regridding algorithms. By `David Huard <https://github.com/huard>`_
- Fix typos (:pull:`191`). By `Jemma Stachelek <https://github.com/jsta>`_
- Copy-editing (:pull:`178`, :pull:`179`). By `RichardScottOZ <https://github.com/RichardScottOZ>`_
Internal changes
~~~~~~~~~~~~~~~~
- Constrain `numba>=0.55.2`. See (:issue:`185`).
- Constrain `shapely<2.0`. See (:issue:`216`).
- Add support for esmpy name change in import. See (:pull:`214`,:issue:`212`)
0.6.3 (29-06-2022)
------------------
Bug fixes
~~~~~~~~~
- Spatial coordinates of `ds_out` are kept within the regridder and transferred to the regridded DataArray or Dataset (:pull:`175`). By `Pascal Bourgault <https://github.com/aulemahal>`_
- Added `numba` as an explicit dependency to fix installation with conda (:pull:`168`). By `Pascal Bourgault <https://github.com/aulemahal>`_
Internal changes
~~~~~~~~~~~~~~~~
- Use `cf-xarray` to guess missing CF coordinates before extracting bounds (:pull:`147`). By `Pascal Bourgault <https://github.com/aulemahal>`_
0.6.2 (23-11-2021)
------------------
Bug fixes
~~~~~~~~~
- The introduction of `sparse`, with `numba` under the hood, restricted input data to little-endian dtypes. For big-endian dtypes, xESMF will convert to little-endian, regrid and convert back (:pull:`135`). By `Pascal Bourgault <https://github.com/aulemahal>`_
- ``SpatialAverager`` did not compute the same weights as ``Regridder`` when source cell areas were not uniform (:pull:`128`). By `David Huard <https://github.com/huard>`_
- Refactor of how the regridding is called internally, to fix a bug with dask and sparse (:pull:`135`). By `Pascal Bourgault <https://github.com/aulemahal>`_
Internal changes
~~~~~~~~~~~~~~~~
- Deprecation of ``regrid_numpy`` and ``regrid_dask`` is scheduled for 0.7.0. All checks on shape, array layout and numba support are now done at call time, rather then at computation time (:pull:`135`).
0.6.1 (23-09-2021)
------------------
Note that this version creates very large dask task graphs that can affect performance for large grids.
Internal changes
~~~~~~~~~~~~~~~~
- Weights are now stored in a ``xr.DataArray`` backed by ``sparse.COO``, which allows to pass them as an argument to the ``xr.apply_ufunc`` and decrease memory usage when using dask. By `Pascal Bourgault <https://github.com/aulemahal>`_
- New dependency `sparse <https://sparse.pydata.org>`_ replacing ``scipy``.
0.6.0 (07-08-2021)
------------------
New features
~~~~~~~~~~~~
- Add the ``skipna`` and ``na_threshold`` options to deal with masks over non-spatial dimensions (:pull:`29`). This is useful when, for example, masks vary over time. By `Stéphane Raynaud <https://github.com/stefraynaud>`_
- Add ``unmapped_to_nan`` argument to regridder frontend. When True, this sets target cells outside the source domain to NaN instead of zero for all regridding methods except nearest neighbour (:pull:`94`). By `Martin Schupfner <https://github.com/sol1105>`_
Bug fixes
~~~~~~~~~
- Drop the PyPi badge and replace by a Conda badge (:pull:`97`). By `Ray Bell <https://github.com/raybellwaves>`_
0.5.3 (04-12-2021)
------------------
Bug fixes
~~~~~~~~~
- Fix regression regarding support for non-CF-compliant coordinate names (:pull:`73`). By `Sam Levang <https://github.com/slevang>`_
- Infer `bounds` dimension name using cf-xarray (:pull:`78`). By `Pascal Bourgault <https://github.com/aulemahal>`_
- Do not regrid variables that are not defined over horizontal dimensions (:pull:`79`). By `Pascal Bourgault <https://github.com/aulemahal>`_
- Ensure locstream dimension name is consistent with `ds_out` (:pull:`81`). By `Mattia Almansi <https://github.com/malmans2>`_
Documentation
~~~~~~~~~~~~~
- Add release instructions (:pull:`75`). By `David Huard <https://github.com/huard>`_
- Update Zenodo DOI badge
0.5.2 (01-20-2021)
------------------
Bug fixes
~~~~~~~~~
* Restore original behavior for lon/lat discovery, uses cf-xarray if lon/lat not found in dataset (:pull:`64`)
* Solve issue of dimension order in dataset (#53) with (:pull:`66`)
0.5.1 (01-11-2021)
------------------
Documentation
~~~~~~~~~~~~~
* Update installation instructions to mention that PyPi only holds xesmf up to version 0.3.0.
New features
~~~~~~~~~~~~
* Regridded xarray.Dataset now preserves the name and attributes of target coordinates (:pull:`60`)
Bug fixes
~~~~~~~~~
* Fix doc build for API/Regridder (:pull:`61`)
0.5.0 (11-11-2020)
------------------
Breaking changes
~~~~~~~~~~~~~~~~
* Deprecate `esmf_grid` in favor of `Grid.from_xarray`
* Deprecate `esmf_locstream` in favor of `LocStream.from_xarray`
* Installation requires numpy>=1.16 and cf-xarray>=0.3.1
New features
~~~~~~~~~~~~
* Create `ESMF.Mesh` objects from `shapely.polygons` (:pull:`24`). By `Pascal Bourgault <https://github.com/aulemahal>`_
* New class `SpatialAverager` offers user-friendly mechanism to average a 2-D field over a polygon. Includes support to handle interior holes and multi-part geometries. (:pull:`24`) By `Pascal Bourgault <https://github.com/aulemahal>`_
* Automatic detection of coordinates and computation of vertices based on cf-xarray. (:pull:`49`) By `Pascal Bourgault <https://github.com/aulemahal>`_
Bug fixes
~~~~~~~~~
* Fix serialization bug when using dask's distributed scheduler (:pull:`39`).
By `Pascal Bourgault <https://github.com/aulemahal>`_.
Internal changes
~~~~~~~~~~~~~~~~
* Subclass `ESMF.Mesh` and create `from_polygon` method
* Subclass `ESMF.Grid` and `ESMF.LocStream` and create `from_xarray` methods.
* New `BaseRegridder` class, with support for `Grid`, `LocStream` and `Mesh` objects. Not all regridding methods are supported for `Mesh` objects.
* Refactor `Regridder` to subclass `BaseRegridder`.
0.4.0 (01-10-2020)
------------------
The git repo is now hosted by pangeo-data (https://github.com/pangeo-data/xESMF)
Breaking changes
~~~~~~~~~~~~~~~~
* By default, weights are not written to disk, but instead kept in memory.
* Installation requires ESMPy 8.0.0 and up.
New features
~~~~~~~~~~~~
* The `Regridder` object now takes a `weights` argument accepting a scipy.sparse COO matrix,
a dictionary, an xarray.Dataset, or a path to a netCDF file created by ESMF. If None, weights
are computed and can be written to disk using the `to_netcdf` method. This `weights` parameter
replaces the `filename` and `reuse_weights` arguments, which are preserved for backward compatibility (:pull:`3`).
By `David Huard <https://github.com/huard>`_ and `Raphael Dussin <https://github.com/raphaeldussin>`_
* Added documentation discussion how to compute weights from a shell using MPI, and reuse from xESMF (:pull:`12`).
By `Raphael Dussin <https://github.com/raphaeldussin>`_
* Add support for masks in :py:func`esmf_grid`. This avoid NaNs to bleed into the interpolated values.
When using a mask and the `conservative` regridding method, use a new method called
`conservative_normed` to properly handle normalization (:pull:`1`).
By `Raphael Dussin <https://github.com/raphaeldussin>`_
0.3.0 (06-03-2020)
------------------
New features
~~~~~~~~~~~~
* Add support for `ESMF.LocStream` `(#81) <https://github.com/JiaweiZhuang/xESMF/pull/81>`_
By `Raphael Dussin <https://github.com/raphaeldussin>`_
0.2.2 (07-10-2019)
------------------
New features
~~~~~~~~~~~~
* Add option to allow degenerated grid cells `(#61) <https://github.com/JiaweiZhuang/xESMF/pull/61>`_
By `Jiawei Zhuang <https://github.com/JiaweiZhuang>`_
0.2.0 (04-08-2019)
------------------
Breaking changes
~~~~~~~~~~~~~~~~
All user-facing APIs in v0.1.x should still work exactly the same. That said, because some internal codes have changed a lot, there might be unexpected edge cases that break current user code. If that happens, you can revert to the previous version by `pip install xesmf==0.1.2` and follow `old docs <https://xesmf.readthedocs.io/en/v0.1.2/>`_.
New features
~~~~~~~~~~~~
* Lazy evaluation on dask arrays (uses :py:func:`xarray.apply_ufunc` and :py:func:`dask.array.map_blocks`)
* Automatic looping over variables in an xarray Dataset
* Add tutorial notebooks on those new features
By `Jiawei Zhuang <https://github.com/JiaweiZhuang>`_
0.1.2 (03-08-2019)
------------------
This release mostly contains internal clean-ups to facilitate future development.
New features
~~~~~~~~~~~~
* Deprecates `regridder.A` in favor of `regridder.weights`
* Speed-up test suites by using coarser grids
* Use parameterized tests when appropriate
* Fix small memory leaks from `ESMF.Grid`
* Properly assert ESMF enums
By `Jiawei Zhuang <https://github.com/JiaweiZhuang>`_
0.1.1 (31-12-2017)
------------------
Initial release.
By `Jiawei Zhuang <https://github.com/JiaweiZhuang>`_
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Jiawei Zhuang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MANIFEST.in
================================================
include LICENSE
include *.rst
graft xesmf
prune .github
prune *.egg-info
prune binder
prune ci
prune doc
exclude *.yaml
exclude *.yml
exclude .*.txt
exclude .gitignore
exclude .pre-commit-config.yaml
exclude .prettierrc.toml
exclude xesmf/_version.py
================================================
FILE: README.rst
================================================
xESMF: Universal Regridder for Geospatial Data
==============================================
|Binder| |conda| |Build Status| |codecov| |docs| |license| |DOI|
xESMF is a Python package for
`regridding <https://climatedataguide.ucar.edu/climate-data-tools-and-analysis/regridding-overview>`_.
It is
- **Powerful**: It uses ESMF_/ESMPy_ as backend and can regrid between **general curvilinear grids**
with all `ESMF regridding algorithms <https://earthsystemmodeling.org/regrid/#regridding-methods>`_,
such as **bilinear**, **conservative** and **nearest neighbour**.
- **Easy-to-use**: It abstracts away ESMF's complicated infrastructure
and provides a simple, high-level API, compatible with xarray_ as well as basic numpy arrays.
- **Fast**: It is faster than ESMPy's original Fortran regridding engine in serial case, and also supports dask_ for `out-of-core, parallel computation <http://xarray.pydata.org/en/stable/dask.html>`_.
Please see `online documentation <http://xesmf.readthedocs.io/en/latest/>`_, or `play with example notebooks on Binder <https://mybinder.org/v2/gh/pangeo-data/xESMF/master?filepath=doc%2Fnotebooks>`_.
For new users, I also recommend reading `How to ask for help <https://xesmf.readthedocs.io/en/latest/#how-to-ask-for-help>`_ and `How to support xESMF <https://xesmf.readthedocs.io/en/latest/#how-to-support-xesmf>`_.
.. _ESMF: https://earthsystemmodeling.org/
.. _ESMPy: http://earthsystemmodeling.org/esmpy/
.. _xarray: http://xarray.pydata.org
.. _dask: https://dask.org/
.. |conda| image:: https://anaconda.org/conda-forge/xesmf/badges/version.svg
:target: https://anaconda.org/conda-forge/xesmf/
.. |Build Status| image:: https://img.shields.io/github/actions/workflow/status/pangeo-data/xESMF/ci.yaml?branch=master
:target: https://github.com/pangeo-data/xESMF/actions
:alt: github-ci build status
.. |codecov| image:: https://codecov.io/gh/pangeo-data/xESMF/branch/master/graph/badge.svg
:target: https://codecov.io/gh/pangeo-data/xESMF
:alt: code coverage
.. |docs| image:: https://readthedocs.org/projects/pangeo-xesmf/badge/?version=latest
:target: http://xesmf.readthedocs.io/en/latest/?badge=latest
:alt: documentation status
.. |license| image:: https://img.shields.io/badge/License-MIT-blue.svg
:target: https://github.com/pangeo-data/xESMF/blob/master/LICENSE
:alt: license
.. |DOI| image:: https://zenodo.org/badge/281126933.svg
:target: https://zenodo.org/badge/latestdoi/281126933
:alt: DOI
.. |Binder| image:: https://mybinder.org/badge_logo.svg
:target: https://mybinder.org/v2/gh/pangeo-data/xESMF/master?filepath=doc%2Fnotebooks
:alt: binder
================================================
FILE: binder/environment.yml
================================================
channels:
- conda-forge
dependencies:
- python=3.7
- esmpy==7.1.0r
- xarray
- dask
- numpy
- scipy
- shapely
- matplotlib
- cartopy
- cf_xarray>=0.3.1
- pip:
- xesmf==0.2.2
================================================
FILE: ci/doc.yml
================================================
name: xesmf
channels:
- conda-forge
dependencies:
# Python pin only to accelerate solving
- python>=3.12
- cf_xarray>=0.5.1
- esmpy >=8.0.0
- numba >=0.55.2
- numpy >=1.16
- shapely
- sparse>=0.8.0
- xarray>=0.17.0
# Doc
- numpydoc
- geopandas
- descartes
- ipython
- Pygments>=2.6
- nbsphinx
- sphinx
- sphinx_rtd_theme
- docutils!=0.18
================================================
FILE: ci/environment-upstream-dev.yml
================================================
name: xesmf
channels:
- conda-forge
dependencies:
- cftime
- codecov
- dask
- esmpy
- netcdf4
- numba
- numpy
- pip
- pre-commit
- pytest
- pytest-cov
- shapely
- sparse>=0.8.0
- pip:
- git+https://github.com/pydata/xarray.git
- git+https://github.com/xarray-contrib/cf-xarray.git
================================================
FILE: ci/environment.yml
================================================
name: xesmf
channels:
- conda-forge
dependencies:
- python>=3.11
- cf_xarray>=0.5.1
- dask
- esmpy
- numba >=0.55.2
- numpy >=1.16
- shapely
- sparse>=0.8.0
- xarray>=0.17.0
# Testing and extras
- cftime
- codecov
- netcdf4
- pip
- pre-commit
- pytest
- pytest-cov
================================================
FILE: codecov.yml
================================================
codecov:
require_ci_to_pass: no
max_report_age: off
comment: false
ignore:
- "xesmf/tests/*"
- "setup.py"
coverage:
precision: 2
round: down
status:
project:
default:
target: 95
informational: true
patch: off
changes: off
================================================
FILE: doc/Makefile
================================================
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python -msphinx
SPHINXPROJ = xESMF
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
================================================
FILE: doc/changes.rst
================================================
.. include:: ../CHANGES.rst
================================================
FILE: doc/conf.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# xESMF documentation build configuration file, created by
# sphinx-quickstart on Sun Dec 17 19:49:04 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import datetime
import xesmf as xe
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'numpydoc',
'sphinx.ext.extlinks',
'sphinx.ext.autosummary',
'sphinx.ext.mathjax',
'nbsphinx',
'IPython.sphinxext.ipython_console_highlighting',
]
extlinks = {
'issue': ('https://github.com/pangeo-data/xESMF/issues/%s', 'GH/%s'),
'pull': ('https://github.com/pangeo-data/xESMF/pull/%s', 'PR/%s'),
}
# IPython.sphinxext.ipython_console_highlighting is required for anaconda.
# See the issue: https://github.com/spatialaudio/nbsphinx/issues/24
# https://stackoverflow.com/questions/12206334/sphinx-autosummary-toctree-contains-reference-to-nonexisting-document-warnings
numpydoc_show_class_members = False
# NOT to sort autodoc functions in alphabetical order
autodoc_member_order = 'bysource'
# avoid automatic execution for notebooks
nbsphinx_execute = 'never'
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
current_year = datetime.datetime.now().year
project = 'xESMF'
copyright = f'{current_year}, Jiawei Zhuang and the xESMF development team'
author = 'Jiawei Zhuang'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = xe.__version__
# The full version, including alpha/beta/rc tags.
release = xe.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '**.ipynb_checkpoints']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'xESMFdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'xESMF.tex', 'xESMF Documentation', 'Jiawei Zhuang', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, 'xesmf', 'xESMF Documentation', [author], 1)]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
'xESMF',
'xESMF Documentation',
author,
'xESMF',
'One line description of project.',
'Miscellaneous',
),
]
================================================
FILE: doc/index.rst
================================================
xESMF: Universal Regridder for Geospatial Data
==============================================
xESMF is a Python package for
`regridding <https://climatedataguide.ucar.edu/climate-data-tools-and-analysis/regridding-overview>`_.
It is
- **Powerful**: It uses ESMF_/ESMPy_ as backend and can regrid between **general curvilinear grids**
with all `ESMF regridding algorithms <https://earthsystemmodeling.org/regrid/#regridding-methods>`_,
such as **bilinear**, **conservative** and **nearest neighbour**.
- **Easy-to-use**: It abstracts away ESMF's complicated infrastructure
and provides a simple, high-level API, compatible with xarray_ as well as basic numpy arrays.
- **Fast**: It is :doc:`faster than <./notebooks/Backend>` ESMPy's original Fortran regridding engine in the serial case, and also supports dask_ for `out-of-core, parallel computation <http://xarray.pydata.org/en/stable/dask.html>`_ .
.. _ESMF: https://earthsystemmodeling.org/
.. _ESMPy: http://earthsystemmodeling.org/esmpy/
.. _xarray: http://xarray.pydata.org
.. _dask: https://dask.org/
Contents
--------
.. toctree::
:maxdepth: 1
:caption: Overview
why
other_tools
limitations
.. toctree::
:maxdepth: 1
:caption: Beginner tutorials
installation
notebooks/Rectilinear_grid
notebooks/Curvilinear_grid
notebooks/Pure_numpy
notebooks/Dataset
.. toctree::
:maxdepth: 1
:caption: Intermediate tutorials
notebooks/Dask
notebooks/Compare_algorithms
notebooks/Reuse_regridder
notebooks/Using_LocStream
notebooks/Masking
large_problems_on_HPC
notebooks/Spatial_Averaging
.. toctree::
:maxdepth: 1
:caption: Technical notes
changes
notebooks/Backend
releases
.. toctree::
:maxdepth: 1
:caption: API
user_api
internal_api
How to ask for help
-------------------
The `GitHub issue tracker <https://github.com/pangeo-data/xESMF/issues>`_ is the primary place for bug reports. If you hit any issues, I recommend the following steps:
- First, `search for existing issues <https://help.github.com/en/articles/searching-issues-and-pull-requests>`_. Other people are likely to hit the same problem and probably have already found the solution. You might also want to search issues in the original repository `<https://github.com/JiaweiZhuang/xESMF/issues>`_.
- For a new bug, please `craft a minimal bug report <https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports>`_ with reproducible code. Use synthetic data or `upload <https://help.github.com/en/articles/file-attachments-on-issues-and-pull-requests>`_ a small sample of input data (~1 MB) so I can quickly reproducible your error.
- For platform-dependent problems (such as kernel dying and installation errors), please also show how to reproduce your system environment, otherwise we have no way to diagnose the issue. The best approach is probably finding an `official Docker image <https://docs.docker.com/docker-hub/official_images/>`_ that is closest to your OS (such as `Ubuntu <https://hub.docker.com/_/ubuntu/>`_ or `CentOS <https://hub.docker.com/_/centos/>`_), and build your Python environment starting with such an image, to see whether the error still exists. Alternatively you can select from public cloud images, such as `Amazon Machine Images <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html>`_ or `Google Cloud Images <https://cloud.google.com/compute/docs/images>`_. If the error only happens on your institution's HPC cluster, please contact the system administrator for help.
For general "how-to" questions that are not bugs, you can also post on `StackOverflow <https://stackoverflow.com/>`_ (ref: `xarray questions <https://stackoverflow.com/questions/tagged/python-xarray>`_).
How to support xESMF
--------------------
Your support in any form will be appreciated. The easy ways (takes several seconds):
- `Give a star <https://help.github.com/en/articles/saving-repositories-with-stars>`_ to its `GitHub repository <https://github.com/pangeo-data/xESMF>`_.
- Share it via social media like Twitter; introduce it to your friends/advisors/students.
More advanced ways:
- Cite xESMF in your scientific publications. Currently the best way is to cite the DOI: https://doi.org/10.5281/zenodo.4294774.
- If you'd like to contribute code, see this `preliminary contributor guide <https://github.com/JiaweiZhuang/xESMF/issues/28>`_. Also see `Contributing to xarray <http://xarray.pydata.org/en/stable/contributing.html>`_ for more backgrounds.
================================================
FILE: doc/installation.rst
================================================
.. _installation-label:
Installation
============
Try on Binder without local installation
----------------------------------------
The `Binder project <https://mybinder.readthedocs.io>`_ provides pre-configured environment in the cloud. You just need a web browser to access it. Please follow the Binder link on `xESMF's GitHub page <https://github.com/pangeo-data/xESMF>`_.
Install on local machine with Conda
-----------------------------------
xESMF requires Python>=3.8. The major dependencies are xarray and ESMPy, and the best way to install them is using Conda_.
Note that the latest xarray releases require Python 3.9 or later.
First, `install miniconda <https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html>`_. Then, we recommend creating a new, clean environment:
.. code-block:: bash
$ conda create -n xesmf_env
$ conda activate xesmf_env
Getting xESMF is as simple as:
.. code-block:: bash
$ conda install -c conda-forge xesmf
We also highly recommend those extra packages for full functionality:
.. code-block:: bash
# to support all features in xESMF
$ conda install -c conda-forge dask netCDF4
# optional dependencies for executing all notebook examples
$ conda install -c conda-forge matplotlib cartopy jupyterlab
Alternatively, you can first install dependencies, and then use ``pip`` to install xESMF:
.. code-block:: bash
$ conda install -c conda-forge esmpy xarray numpy shapely cf_xarray sparse numba
$ pip install git+https://github.com/pangeo-data/xesmf.git
This will install the latest version from the github repo. To install a specific release, append the version tag to the url (e.g. `@v0.5.0`).
Notes about ESMpy
-----------------
* ESMpy 8.4 is only compatible with xESMF >= 0.7.
* ESMpy must be installed through Conda or compiled manually; it is not available through PyPI. When installing xESMF with pip, the ESMpy package must be manually installed first.
Testing your installation
-------------------------
xESMF itself is a lightweight package, but its dependency ESMPy is a quite heavy and sometimes might be installed incorrectly. To validate & debug your installation, you can use pytest to run the test suites:
.. code-block:: bash
$ conda install pytest
$ pytest -v --pyargs xesmf # should all pass
A common cause of error (especially for HPC cluster users) is that pre-installed modules like NetCDF, MPI, and ESMF are incompatible with the conda-installed equivalents. Make sure you have a clean environment when running ``conda install`` (do not ``module load`` other libraries). See `this issue <https://github.com/JiaweiZhuang/xESMF/issues/55#issuecomment-514298498>`_ for more discussions.
Notes for Windows users
-----------------------
The ESMPy conda package is usually only available for Linux and Mac OSX.
Builds for windows have been made for some versions (8.4.2).
Windows users can try the
`Linux subsystem <https://docs.microsoft.com/en-us/windows/wsl/about>`_
or `docker-miniconda <https://hub.docker.com/r/continuumio/miniconda3/>`_ .
Installing scientific software on Windows can often be a pain, and
`Docker <https://www.docker.com>`_ is a pretty good workaround.
It takes some time to learn but worths the effort.
Check out this `tutorial on using Docker with Anaconda <https://towardsdatascience.com/how-docker-can-help-you-become-a-more-effective-data-scientist-7fc048ef91d5>`_.
This problem is being investigated. See `this other issue <https://github.com/conda-forge/esmf-feedstock/pull/1198>`_.
Install development version from GitHub repo
--------------------------------------------
To get the latest version that is not uploaded to PyPI_ yet::
$ pip install --upgrade git+https://github.com/pangeo-data/xESMF.git
Developers can track source code change::
$ git clone https://github.com/pangeo-data/xESMF.git
$ cd xESMF
$ pip install -e .
.. _xarray: http://xarray.pydata.org
.. _ESMPy: http://earthsystemmodeling.org/esmpy/
.. _Conda: https://docs.conda.io/
.. _PyPI: https://pypi.python.org/pypi
.. _NESII: https://www.esrl.noaa.gov/gsd/nesii/
================================================
FILE: doc/internal_api.rst
================================================
Internal API
############
frontend
========
.. automodule:: xesmf.frontend
:members:
backend
=======
.. automodule:: xesmf.backend
:members:
smm
===
.. automodule:: xesmf.smm
:members:
================================================
FILE: doc/large_problems_on_HPC.rst
================================================
.. _largeproblems-label:
.. |polarstereo| image:: images/elevation_southpolarstero.png
:width: 600
:alt: elevation in polar stereographic
.. |regular| image:: images/elevation_regulargrid.png
:width: 600
:alt: elevation on regular lat/lon grid
Solving large problems using HPC
================================
In some cases, the sizes of the source and target grids lead to weights that either take
too long to compute or can't fit into memory on a regular desktop/laptop machine. But fear not,
there are solutions to solve large regridding problems, provided you have access to a High
Performance Computing machine. Your ESMF installation (from conda or equivalent) comes with
command line tools (`ESMF_RegridWeightGen and ESMF_Regrid <http://www.earthsystemmodeling.org/esmf_releases/public/ESMF_8_0_0/ESMF_refdoc/node3.html>`_) that can be executed in parallel with
MPI. This allows very large regridding to be performed in minutes on hundred of compute cores.
Using these tools, we are able to regrid data at 500 meters resolution (13300x13300 pts) from
a South Polar Stereographic projection to a 15' regular longitude/latitude grid (6720x86400 pts).
The original:
|polarstereo|
and after regridding:
|regular|
Although these tools are very performant, they lack critical documentation which makes them
hard to understand and operate. We're going to try to bridge those gaps with some real-life
examples.
The roadblocks that you are most likely to find on your way are related to netcdf attributes
required by the ESMF tools. Error messages are not very informative and one may need to read the
source code to figure out what the problem is. The first **trick** you need to know is that
geographical coordinates both need **units** netcdf attributes and these units can only be
from the lists:
* *degrees_east, degree_east, degrees_E, degree_E, degreesE, degreeE* for longitude
* *degrees_north, degree_north, degrees_N, degree_N, degreesN, degreeN* for latitude
Otherwise, ESMF will fail with an error along the lines of *file type not recognized*.
For conservative regridding, the units of the longitude and latitude arrays at the cell
corners have to be *grid_corner_lon* and *grid_corner_lat*.
.. compound::
output from **ncdump -h** on your netcdf file should look like::
variables:
double lat(lat) ;
lat:_FillValue = 1.e+20 ;
lat:units = "degrees_north" ;
double lon(lon) ;
lon:_FillValue = 1.e+20 ;
lon:units = "degrees_east" ;
dimensions and coordinates names do not need to be the same and coordinates can be 2d.
Creating weights on HPC and using them in xESMF
-----------------------------------------------
With your source and destination grids ready, you can now generate weights on your HPC system that
you can later use in xESMF by providing the **filename** and **reuse_weights=True** when creating
a regridder. The invocation to the weights generation on a MPI parallel system using 252 cores
will look like:
.. code-block:: bash
$ mpirun -np 252 ESMF_RegridWeightGen -s source.nc -d destination.nc -w weights.nc -m bilinear
In this example, we use bilinear regridding but all the methods available in xESMF are here too.
You can then import your weights generated on your HPC system in xESMF with:
.. code-block:: python
import xarray as xr
import xesmf as xe
ds_in = xr.open_dataset("source.nc")
ds_out = xr.open_dataset("destination.nc")
regridder = xe.Regridder(ds_in, ds_out, "bilinear", filename="weights.nc", reuse_weights=True)
There is a lot of options you can provide to **ESMF_RegridWeightGen** and you can have a list using:
.. code-block:: bash
$ ESMF_RegridWeightGen --help
Some of particular interest are:
* **--netcdf4**: netcdf3 cannot handle very large files that can be produced here
* **--src_regional / --dst_regional**: if one of your grid is not periodic in longitude
Regrid variable(s) on HPC system
--------------------------------
If the weights you have generated don't fit into memory when using xESMF (e.g. you have an error of the
type *buffer size too small*), you still have the option to do the regridding of your variable on
the HPC using **ESMF_Regrid**. Here again, there is a **second trick** that you need to know:
.. compound::
all the variables you want to regrid need to have a netcdf attribute named **coordinates**
that gives the list of its geographical coordinates, e.g.::
variables:
double lat(lat) ;
lat:_FillValue = 1.e+20 ;
lat:units = "degrees_north" ;
double lon(lon) ;
lon:_FillValue = 1.e+20 ;
lon:units = "degrees_east" ;
short elevation(lat, lon) ;
elevation:_FillValue = 32767s ;
elevation:units = "m" ;
elevation:standard_name = "height_above_reference_ellipsoid" ;
elevation:long_name = "Elevation relative to sea level" ;
elevation:coordinates = "lon lat" ;
Also specifying a _FillValue explicitly instead of a NaN is also a good idea ;)
**ESMF_Regrid** will overwrite the destination.nc file and add the regridded variables so you
may want to make a copy in case (say output.nc). We can now invoke the regridding for the
variable *elevation* on the HPC using:
.. code-block:: bash
$ mpirun -np 720 ESMF_Regrid -s source.nc -d output.nc -m bilinear --src_var elevation --dst_var elevation --netcdf4
And this gets the job done! If for some reason, **ESMF_Regrid** dies with a MPI error, try increasing the
number of compute cores. Similarly, you can get the numerous available options with:
.. code-block:: bash
$ ESMF_Regrid --help
There is a lot to unpack when it comes to the options so this might be a good time to start
exploring by yourself. Hopefully this gave you enough information to work it out.
Technical point: mpi4py considerations
--------------------------------------
If your HPC system does not provide a satisfying ESMF module, you may need to install it yourself
through conda. This is fine and should mostly work smoothly except that you may have some MPI issues
or conflicts. To use ESMF_Regrid, you will need to activate your conda env but it is likely that the
mpirun in it will not work on your HPC system because it hasn't been set up properly.
The solution is to install mpi4py from scratch and customize its mpi.cfg file to your MPI libraries
specifications. The block to add to mpi.cfg should look like this:
.. code-block:: bash
[gaea-gnu]
mpi_dir = /opt/cray/pe/mpt/7.7.11/gni/mpich-gnu/8.2
include_dirs = %(mpi_dir)s/include
libraries = mpich
library_dirs = %(mpi_dir)s/lib
runtime_library_dirs = %(mpi_dir)s/lib
mpicc = /opt/gcc/8.2.0/bin/gcc
mpicxx = /opt/gcc/8.2.0/bin/g++
And then recompile mpi4py from scratch:
.. code-block:: bash
wget https://bitbucket.org/mpi4py/mpi4py/downloads/mpi4py-3.0.3.tar.gz
tar -zxf mpi4py-3.0.3.tar.gz
conda activate myenv
cat gaea_mpi.cfg >> mpi4py-3.0.3/mpi.cfg
pushd mpi4py-3.0.3
python setup.py build --mpi=gaea-gnu
python setup.py install
================================================
FILE: doc/limitations.rst
================================================
Current limitations
===================
.. _irregular_meshes-label:
Irregular meshes
----------------
ESMPy is actually able to deal with general irregular meshes
(`example <http://www.earthsystemmodeling.org/esmf_releases/
last_built/esmpy_doc/html/examples.html#create-a-5-element-mesh>`_),
but designing an elegant front-end for that is very challenging.
Plain 2D arrays cannot describe irregular meshes.
There needs to be additional information for connectivity, as suggested by
`UGRID Conventions <http://ugrid-conventions.github.io/ugrid-conventions/>`_.
xESMF supports quadrilateral grids and has limited support of
triangular or hexagonal meshes. xESMF also supports complex polygonal
meshes, but only in the context of regional averaging.
xarray's data model, although powerful, can only describe quadrilateral grids
(including multi-tile quadrilateral grids like the cubed-sphere).
If there is an elegant data model in Python for irregular meshes, interfacing
with ESMPy should not be very difficult. Pull requests along these lines are welcome.
Vector regridding
-----------------
Like almost all regridding packages, xESMF assumes scalar fields.
The most common way to remap winds is to rotate/re-decompose the
wind components (U and V) to the new direction,
and then regrid each component individually using a scalar regridding function.
Exact conservation of vector properities (like divergence and vorticity)
is beyond the scope of almost all regridding packages.
Using bilinear algorithm on each component should lead to OK results in most cases.
================================================
FILE: doc/make.bat
================================================
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=python -msphinx
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=xESMF
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
echo.then set the SPHINXBUILD environment variable to point to the full
echo.path of the 'sphinx-build' executable. Alternatively you may add the
echo.Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
================================================
FILE: doc/notebooks/Backend.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# xESMF backend usage and benchmark\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"xESMF isn't just a wrapper of ESMPy. It only uses ESMPy to generate regridding\n",
"weights, but has its own Scipy-based method for applying weights (see\n",
"[more about regridding weights](./Reuse_regridder.ipynb#Why-applying-regridding-is-so-fast?)).\n",
"\n",
"We switch to the Scipy method because its serial performance is much higher than\n",
"ESMPy's own engine and can also reuse weights\n",
"([issue#2](https://github.com/JiaweiZhuang/xESMF/issues/2)). ESMPy's native\n",
"method is available in the backend, mainly for benchmarking Scipy results in\n",
"unit tests.\n",
"\n",
"Here we show how to use xESMF backend and compare the performance of two\n",
"methods. Note that the backend is still pretty easy to use compared to the\n",
"original ESMPy -- it just doesn't have a fancy API and cannot deal with xarray\n",
"metadata.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import numpy as np\n",
"import xesmf as xe\n",
"\n",
"# backend functions\n",
"from xesmf.backend import (\n",
" Grid,\n",
" esmf_regrid_build,\n",
" esmf_regrid_apply,\n",
")\n",
"from xesmf.smm import read_weights, apply_weights"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prepare data\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We use the same data as in the\n",
"[reusing regridder example](./Reuse_regridder.ipynb), but convert xarray DataSet\n",
"to pure numpy arrays to work with the backend.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"ds_in = xe.util.grid_2d(\n",
" -120, 120, 0.4, -60, 60, 0.3 # longitude range and resolution\n",
") # latitude range and resolution\n",
"ds_out = xe.util.grid_2d(-120, 120, 0.6, -60, 60, 0.4)\n",
"ds_in.coords[\"time\"] = np.arange(1, 11)\n",
"ds_in.coords[\"lev\"] = np.arange(1, 51)\n",
"ds_in[\"data2D\"] = xe.data.wave_smooth(ds_in[\"lon\"], ds_in[\"lat\"])\n",
"ds_in[\"data4D\"] = ds_in[\"time\"] * ds_in[\"lev\"] * ds_in[\"data2D\"]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(10, 50, 400, 600)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# backend only accepts pure numpy array\n",
"lon_in = ds_in[\"lon\"].values\n",
"lat_in = ds_in[\"lat\"].values\n",
"\n",
"lon_out = ds_out[\"lon\"].values\n",
"lat_out = ds_out[\"lat\"].values\n",
"\n",
"data_in = ds_in[\"data4D\"].values\n",
"data_in.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Make ESMF Grid objects\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"grid_in = Grid.from_xarray(lon_in.T, lat_in.T)\n",
"grid_out = Grid.from_xarray(lon_out.T, lat_out.T)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is a native ESMPy Grid object:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"xesmf.backend.Grid"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(grid_in)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We pass the transpose (`lon.T`) because ESMPy prefer Fortran-ordering to\n",
"C-ordering (see this\n",
"[issue](https://github.com/nawendt/esmpy-tutorial/issues/4)).\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" C_CONTIGUOUS : True\n",
" F_CONTIGUOUS : False\n",
" OWNDATA : True\n",
" WRITEABLE : True\n",
" ALIGNED : True\n",
" WRITEBACKIFCOPY : False\n",
" UPDATEIFCOPY : False"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lon_in.flags # numpy arrays are mostly C-ordered"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" C_CONTIGUOUS : False\n",
" F_CONTIGUOUS : True\n",
" OWNDATA : False\n",
" WRITEABLE : True\n",
" ALIGNED : True\n",
" WRITEBACKIFCOPY : False\n",
" UPDATEIFCOPY : False"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lon_in.T.flags # a memory view on its tranpose would be Fortran-ordered"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Compute weights\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"filename = \"test_weights.nc\" # weight filename\n",
"if os.path.exists(filename):\n",
" os.remove(filename) # ESMPy will complain if the file exists"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Computing weights takes ~7s, as in the\n",
"[reusing regridder example](./Reuse_regridder.ipynb#Build-Regridder).\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 4.08 s, sys: 207 ms, total: 4.29 s\n",
"Wall time: 4.35 s\n"
]
}
],
"source": [
"%%time\n",
"regrid = esmf_regrid_build(grid_in, grid_out, 'bilinear',\n",
" extra_dims=[50, 10], # reversed to Fortran-ordering\n",
" filename=filename)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It returns a native ESMPy Regrid object:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ESMF.api.regrid.Regrid"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(regrid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It also writes weights to disk so we can then read them back for Scipy.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"netcdf test_weights {\n",
"dimensions:\n",
"\tn_s = 480000 ;\n",
"variables:\n",
"\tdouble S(n_s) ;\n",
"\tint col(n_s) ;\n",
"\tint row(n_s) ;\n",
"}\n"
]
}
],
"source": [
"%%bash\n",
"ncdump -h test_weights.nc"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Apply weights using ESMPy backend\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It takes ~3s with ESMPy's native method.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 1.59 s, sys: 2.51 s, total: 4.1 s\n",
"Wall time: 12.3 s\n"
]
}
],
"source": [
"%%time\n",
"data_out_esmpy = esmf_regrid_apply(regrid, data_in.T).T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The first `.T` converts C-ordering to F-ordering for ESMPy, and the second `.T`\n",
"converts the result back to C-ordering. It just gets a memory view and thus\n",
"incurs almost no overhead.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" C_CONTIGUOUS : True\n",
" F_CONTIGUOUS : False\n",
" OWNDATA : False\n",
" WRITEABLE : True\n",
" ALIGNED : True\n",
" WRITEBACKIFCOPY : False\n",
" UPDATEIFCOPY : False"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_out_esmpy.flags"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(10, 50, 300, 400)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_out_esmpy.shape # broadcasted over extra dimensions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Apply weights using Scipy backend\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Read weights back for Scipy. `read_weights` needs to know the shape of the\n",
"sparse matrix, i.e. how many points in input and output grids.\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<120000x240000 sparse matrix of type '<class 'numpy.float64'>'\n",
"\twith 480000 stored elements in COOrdinate format>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weights = read_weights(filename, lon_in.size, lon_out.size)\n",
"weights"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`apply_weights` needs to know shape of the output grid.\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(300, 400)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lon_out.shape"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 842 ms, sys: 776 ms, total: 1.62 s\n",
"Wall time: 6.07 s\n"
]
}
],
"source": [
"%%time\n",
"data_out_scipy = apply_weights(weights, data_in, lon_in.shape, lon_out.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is several times faster than ESMPy's native method. The conclusion seems to\n",
"be pretty robust across different platforms (feel free to verify on your own),\n",
"so we choose Scipy as the default backend.\n",
"\n",
"A likely explanation for this performance discrepancy is, the original ESMF is\n",
"optimized for large processor counts (~1000 CPUs) at the expense of serial\n",
"performance (ESMF team, personal communication).\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(10, 50, 300, 400)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_out_scipy.shape # broadcasted over extra dimensions"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"np.testing.assert_equal(data_out_scipy, data_out_esmpy) # exactly the same"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"os.remove(filename) # clean-up"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.2"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"toc_cell": false,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
================================================
FILE: doc/notebooks/Compare_algorithms.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Comparison of six regridding algorithms\n",
"\n",
"xESMF exposes five different regridding algorithms from the ESMF library:\n",
"\n",
"- `bilinear`: `ESMF.RegridMethod.BILINEAR`\n",
"- `conservative`: `ESMF.RegridMethod.CONSERVE`\n",
"- `conservative_normed`: `ESMF.RegridMethod.CONSERVE`\n",
"- `patch`: `ESMF.RegridMethod.PATCH`\n",
"- `nearest_s2d`: `ESMF.RegridMethod.NEAREST_STOD`\n",
"- `nearest_d2s`: `ESMF.RegridMethod.NEAREST_DTOS`\n",
"\n",
"where `conservative_normed` is just the `conservative` method with the\n",
"normalization set to `ESMF.NormType.FRACAREA` instead of the default\n",
"`norm_type=ESMF.NormType.DSTAREA`.\n",
"\n",
"This notebook demonstrates how these algorithms behave in different situations.\n",
"\n",
"## Notes\n",
"\n",
"- `bilinear` and `conservative` should be the most commonly used methods. They\n",
" are both monotonic (i.e. will not create new maximum/minimum).\n",
"- Nearest neighbour methods, either source to destination (s2d) or destination\n",
" to source (d2s), could be useful in special cases. Keep in mind that d2s is\n",
" highly non-monotonic.\n",
"- Patch is ESMF's unique method, producing highly smooth results but quite slow.\n",
"- From the ESMF documentation:\n",
"\n",
" > The weight $w_{ij}$ for a particular source cell $i$ and destination cell\n",
" > $j$ are calculated as $w_{ij}=f_{ij} * A_{si}/A_{dj}$. In this equation\n",
" > $f_{ij}$ is the fraction of the source cell $i$ contributing to destination\n",
" > cell $j$, and $A_{si}$ and $A_{dj}$ are the areas of the source and\n",
" > destination cells.\n",
"\n",
" For `conservative_normed`,\n",
"\n",
" > ... then the weights are further divided by the destination fraction. In\n",
" > other words, in that case $w_{ij}=f_{ij} * A_{si}/(A_{dj}*D_j)$ where $D_j$\n",
" > is fraction of the destination cell that intersects the unmasked source\n",
" > grid.\n",
"\n",
"Detailed explanations are available on\n",
"[ESMPy documentation](http://www.earthsystemmodeling.org/esmf_releases/last_built/esmpy_doc/html/api.html#regridding).\n",
"\n",
"## Preparation\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"import cartopy.crs as ccrs\n",
"import numpy as np\n",
"import xarray as xr\n",
"import xesmf as xe\n",
"\n",
"method_list = [\n",
" \"bilinear\",\n",
" \"conservative\",\n",
" \"conservative_normed\",\n",
" \"nearest_s2d\",\n",
" \"nearest_d2s\",\n",
" \"patch\",\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"ds_in = xe.util.grid_global(20, 15) # input grid\n",
"ds_fine = xe.util.grid_global(4, 4) # high-resolution target grid\n",
"ds_coarse = xe.util.grid_global(30, 20) # low-resolution target grid"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Make a wave field that is widely used in regridding benchmarks.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><svg style=\"position: absolute; width: 0; height: 0; overflow: hidden\">\n",
"<defs>\n",
"<symbol id=\"icon-database\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z\"></path>\n",
"<path d=\"M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"<path d=\"M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z\"></path>\n",
"</symbol>\n",
"<symbol id=\"icon-file-text2\" viewBox=\"0 0 32 32\">\n",
"<path d=\"M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z\"></path>\n",
"<path d=\"M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"<path d=\"M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z\"></path>\n",
"</symbol>\n",
"</defs>\n",
"</svg>\n",
"<style>/* CSS stylesheet for displaying xarray objects in jupyterlab.\n",
" *\n",
" */\n",
"\n",
":root {\n",
" --xr-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));\n",
" --xr-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));\n",
" --xr-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));\n",
" --xr-border-color: var(--jp-border-color2, #e0e0e0);\n",
" --xr-disabled-color: var(--jp-layout-color3, #bdbdbd);\n",
" --xr-background-color: var(--jp-layout-color0, white);\n",
" --xr-background-color-row-even: var(--jp-layout-color1, white);\n",
" --xr-background-color-row-odd: var(--jp-layout-color2, #eeeeee);\n",
"}\n",
"\n",
"html[theme=dark],\n",
"body.vscode-dark {\n",
" --xr-font-color0: rgba(255, 255, 255, 1);\n",
" --xr-font-color2: rgba(255, 255, 255, 0.54);\n",
" --xr-font-color3: rgba(255, 255, 255, 0.38);\n",
" --xr-border-color: #1F1F1F;\n",
" --xr-disabled-color: #515151;\n",
" --xr-background-color: #111111;\n",
" --xr-background-color-row-even: #111111;\n",
" --xr-background-color-row-odd: #313131;\n",
"}\n",
"\n",
".xr-wrap {\n",
" display: block;\n",
" min-width: 300px;\n",
" max-width: 700px;\n",
"}\n",
"\n",
".xr-text-repr-fallback {\n",
" /* fallback to plain text repr when CSS is not injected (untrusted notebook) */\n",
" display: none;\n",
"}\n",
"\n",
".xr-header {\n",
" padding-top: 6px;\n",
" padding-bottom: 6px;\n",
" margin-bottom: 4px;\n",
" border-bottom: solid 1px var(--xr-border-color);\n",
"}\n",
"\n",
".xr-header > div,\n",
".xr-header > ul {\n",
" display: inline;\n",
" margin-top: 0;\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-obj-type,\n",
".xr-array-name {\n",
" margin-left: 2px;\n",
" margin-right: 10px;\n",
"}\n",
"\n",
".xr-obj-type {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-sections {\n",
" padding-left: 0 !important;\n",
" display: grid;\n",
" grid-template-columns: 150px auto auto 1fr 20px 20px;\n",
"}\n",
"\n",
".xr-section-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-section-item input {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-item input + label {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label {\n",
" cursor: pointer;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-item input:enabled + label:hover {\n",
" color: var(--xr-font-color0);\n",
"}\n",
"\n",
".xr-section-summary {\n",
" grid-column: 1;\n",
" color: var(--xr-font-color2);\n",
" font-weight: 500;\n",
"}\n",
"\n",
".xr-section-summary > span {\n",
" display: inline-block;\n",
" padding-left: 0.5em;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label {\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-section-summary-in + label:before {\n",
" display: inline-block;\n",
" content: '►';\n",
" font-size: 11px;\n",
" width: 15px;\n",
" text-align: center;\n",
"}\n",
"\n",
".xr-section-summary-in:disabled + label:before {\n",
" color: var(--xr-disabled-color);\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label:before {\n",
" content: '▼';\n",
"}\n",
"\n",
".xr-section-summary-in:checked + label > span {\n",
" display: none;\n",
"}\n",
"\n",
".xr-section-summary,\n",
".xr-section-inline-details {\n",
" padding-top: 4px;\n",
" padding-bottom: 4px;\n",
"}\n",
"\n",
".xr-section-inline-details {\n",
" grid-column: 2 / -1;\n",
"}\n",
"\n",
".xr-section-details {\n",
" display: none;\n",
" grid-column: 1 / -1;\n",
" margin-bottom: 5px;\n",
"}\n",
"\n",
".xr-section-summary-in:checked ~ .xr-section-details {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-array-wrap {\n",
" grid-column: 1 / -1;\n",
" display: grid;\n",
" grid-template-columns: 20px auto;\n",
"}\n",
"\n",
".xr-array-wrap > label {\n",
" grid-column: 1;\n",
" vertical-align: top;\n",
"}\n",
"\n",
".xr-preview {\n",
" color: var(--xr-font-color3);\n",
"}\n",
"\n",
".xr-array-preview,\n",
".xr-array-data {\n",
" padding: 0 5px !important;\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-array-data,\n",
".xr-array-in:checked ~ .xr-array-preview {\n",
" display: none;\n",
"}\n",
"\n",
".xr-array-in:checked ~ .xr-array-data,\n",
".xr-array-preview {\n",
" display: inline-block;\n",
"}\n",
"\n",
".xr-dim-list {\n",
" display: inline-block !important;\n",
" list-style: none;\n",
" padding: 0 !important;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list li {\n",
" display: inline-block;\n",
" padding: 0;\n",
" margin: 0;\n",
"}\n",
"\n",
".xr-dim-list:before {\n",
" content: '(';\n",
"}\n",
"\n",
".xr-dim-list:after {\n",
" content: ')';\n",
"}\n",
"\n",
".xr-dim-list li:not(:last-child):after {\n",
" content: ',';\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-has-index {\n",
" font-weight: bold;\n",
"}\n",
"\n",
".xr-var-list,\n",
".xr-var-item {\n",
" display: contents;\n",
"}\n",
"\n",
".xr-var-item > div,\n",
".xr-var-item label,\n",
".xr-var-item > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-even);\n",
" margin-bottom: 0;\n",
"}\n",
"\n",
".xr-var-item > .xr-var-name:hover span {\n",
" padding-right: 5px;\n",
"}\n",
"\n",
".xr-var-list > li:nth-child(odd) > div,\n",
".xr-var-list > li:nth-child(odd) > label,\n",
".xr-var-list > li:nth-child(odd) > .xr-var-name span {\n",
" background-color: var(--xr-background-color-row-odd);\n",
"}\n",
"\n",
".xr-var-name {\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-var-dims {\n",
" grid-column: 2;\n",
"}\n",
"\n",
".xr-var-dtype {\n",
" grid-column: 3;\n",
" text-align: right;\n",
" color: var(--xr-font-color2);\n",
"}\n",
"\n",
".xr-var-preview {\n",
" grid-column: 4;\n",
"}\n",
"\n",
".xr-var-name,\n",
".xr-var-dims,\n",
".xr-var-dtype,\n",
".xr-preview,\n",
".xr-attrs dt {\n",
" white-space: nowrap;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-var-name:hover,\n",
".xr-var-dims:hover,\n",
".xr-var-dtype:hover,\n",
".xr-attrs dt:hover {\n",
" overflow: visible;\n",
" width: auto;\n",
" z-index: 1;\n",
"}\n",
"\n",
".xr-var-attrs,\n",
".xr-var-data {\n",
" display: none;\n",
" background-color: var(--xr-background-color) !important;\n",
" padding-bottom: 5px !important;\n",
"}\n",
"\n",
".xr-var-attrs-in:checked ~ .xr-var-attrs,\n",
".xr-var-data-in:checked ~ .xr-var-data {\n",
" display: block;\n",
"}\n",
"\n",
".xr-var-data > table {\n",
" float: right;\n",
"}\n",
"\n",
".xr-var-name span,\n",
".xr-var-data,\n",
".xr-attrs {\n",
" padding-left: 25px !important;\n",
"}\n",
"\n",
".xr-attrs,\n",
".xr-var-attrs,\n",
".xr-var-data {\n",
" grid-column: 1 / -1;\n",
"}\n",
"\n",
"dl.xr-attrs {\n",
" padding: 0;\n",
" margin: 0;\n",
" display: grid;\n",
" grid-template-columns: 125px auto;\n",
"}\n",
"\n",
".xr-attrs dt,\n",
".xr-attrs dd {\n",
" padding: 0;\n",
" margin: 0;\n",
" float: left;\n",
" padding-right: 10px;\n",
" width: auto;\n",
"}\n",
"\n",
".xr-attrs dt {\n",
" font-weight: normal;\n",
" grid-column: 1;\n",
"}\n",
"\n",
".xr-attrs dt:hover span {\n",
" display: inline-block;\n",
" background: var(--xr-background-color);\n",
" padding-right: 10px;\n",
"}\n",
"\n",
".xr-attrs dd {\n",
" grid-column: 2;\n",
" white-space: pre-wrap;\n",
" word-break: break-all;\n",
"}\n",
"\n",
".xr-icon-database,\n",
".xr-icon-file-text2 {\n",
" display: inline-block;\n",
" vertical-align: middle;\n",
" width: 1em;\n",
" height: 1.5em !important;\n",
" stroke-width: 0;\n",
" stroke: currentColor;\n",
" fill: currentColor;\n",
"}\n",
"</style><pre class='xr-text-repr-fallback'><xarray.Dataset>\n",
"Dimensions: (y: 12, x: 18, y_b: 13, x_b: 19)\n",
"Coordinates:\n",
" lon (y, x) float64 -170.0 -150.0 -130.0 -110.0 ... 130.0 150.0 170.0\n",
" lat (y, x) float64 -82.5 -82.5 -82.5 -82.5 ... 82.5 82.5 82.5 82.5\n",
" lon_b (y_b, x_b) int64 -180 -160 -140 -120 -100 ... 100 120 140 160 180\n",
" lat_b (y_b, x_b) int64 -90 -90 -90 -90 -90 -90 -90 ... 90 90 90 90 90 90\n",
"Dimensions without coordinates: y, x, y_b, x_b\n",
"Data variables:\n",
" data (y, x) float64 2.016 2.009 1.997 1.987 ... 1.987 1.997 2.009 2.016</pre><div class='xr-wrap' hidden><div class='xr-header'><div class='xr-obj-type'>xarray.Dataset</div></div><ul class='xr-sections'><li class='xr-section-item'><input id='section-73b0f2e5-a4dd-4fc5-8984-985d84605891' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-73b0f2e5-a4dd-4fc5-8984-985d84605891' class='xr-section-summary' title='Expand/collapse section'>Dimensions:</label><div class='xr-section-inline-details'><ul class='xr-dim-list'><li><span>y</span>: 12</li><li><span>x</span>: 18</li><li><span>y_b</span>: 13</li><li><span>x_b</span>: 19</li></ul></div><div class='xr-section-details'></div></li><li class='xr-section-item'><input id='section-6ca2a65c-0554-4617-a917-8190bfc3daaf' class='xr-section-summary-in' type='checkbox' checked><label for='section-6ca2a65c-0554-4617-a917-8190bfc3daaf' class='xr-section-summary' >Coordinates: <span>(4)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>lon</span></div><div class='xr-var-dims'>(y, x)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>-170.0 -150.0 ... 150.0 170.0</div><input id='attrs-0d07967d-2db3-4e90-9439-43d8d0be00c2' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-0d07967d-2db3-4e90-9439-43d8d0be00c2' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-b9056b7a-fab9-47fc-a204-9a9c50462810' class='xr-var-data-in' type='checkbox'><label for='data-b9056b7a-fab9-47fc-a204-9a9c50462810' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>longitude</dd></dl></div><div class='xr-var-data'><pre>array([[-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.],\n",
" [-170., -150., -130., -110., -90., -70., -50., -30., -10.,\n",
" 10., 30., 50., 70., 90., 110., 130., 150., 170.]])</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lat</span></div><div class='xr-var-dims'>(y, x)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>-82.5 -82.5 -82.5 ... 82.5 82.5</div><input id='attrs-8111a020-c254-4730-974f-3799c3334350' class='xr-var-attrs-in' type='checkbox' ><label for='attrs-8111a020-c254-4730-974f-3799c3334350' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-0e2f5e97-bcc6-4710-b450-147df3bc5ce6' class='xr-var-data-in' type='checkbox'><label for='data-0e2f5e97-bcc6-4710-b450-147df3bc5ce6' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'><dt><span>standard_name :</span></dt><dd>latitude</dd></dl></div><div class='xr-var-data'><pre>array([[-82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5,\n",
" -82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5, -82.5],\n",
" [-67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5,\n",
" -67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5, -67.5],\n",
" [-52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5,\n",
" -52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5, -52.5],\n",
" [-37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5,\n",
" -37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5, -37.5],\n",
" [-22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5,\n",
" -22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5, -22.5],\n",
" [ -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5,\n",
" -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5, -7.5],\n",
" [ 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5,\n",
" 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5],\n",
" [ 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5,\n",
" 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5, 22.5],\n",
" [ 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5,\n",
" 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5],\n",
" [ 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5,\n",
" 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5, 52.5],\n",
" [ 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5,\n",
" 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5, 67.5],\n",
" [ 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5,\n",
" 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5, 82.5]])</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lon_b</span></div><div class='xr-var-dims'>(y_b, x_b)</div><div class='xr-var-dtype'>int64</div><div class='xr-var-preview xr-preview'>-180 -160 -140 -120 ... 140 160 180</div><input id='attrs-f55db80b-e551-45a5-9a08-4507125c3e5b' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-f55db80b-e551-45a5-9a08-4507125c3e5b' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-f701a3bd-fc52-4fd2-ba2d-4c1bed0f1c9a' class='xr-var-data-in' type='checkbox'><label for='data-f701a3bd-fc52-4fd2-ba2d-4c1bed0f1c9a' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180],\n",
" [-180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20,\n",
" 40, 60, 80, 100, 120, 140, 160, 180]])</pre></div></li><li class='xr-var-item'><div class='xr-var-name'><span>lat_b</span></div><div class='xr-var-dims'>(y_b, x_b)</div><div class='xr-var-dtype'>int64</div><div class='xr-var-preview xr-preview'>-90 -90 -90 -90 -90 ... 90 90 90 90</div><input id='attrs-36ec1589-b6c7-4fa7-a0ed-95e10446db60' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-36ec1589-b6c7-4fa7-a0ed-95e10446db60' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-170dd816-4fd2-498f-8782-3f50a4712dfb' class='xr-var-data-in' type='checkbox'><label for='data-170dd816-4fd2-498f-8782-3f50a4712dfb' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[-90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,\n",
" -90, -90, -90, -90, -90, -90],\n",
" [-75, -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,\n",
" -75, -75, -75, -75, -75, -75],\n",
" [-60, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,\n",
" -60, -60, -60, -60, -60, -60],\n",
" [-45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,\n",
" -45, -45, -45, -45, -45, -45],\n",
" [-30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,\n",
" -30, -30, -30, -30, -30, -30],\n",
" [-15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,\n",
" -15, -15, -15, -15, -15, -15],\n",
" [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0],\n",
" [ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n",
" 15, 15, 15, 15, 15, 15],\n",
" [ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,\n",
" 30, 30, 30, 30, 30, 30],\n",
" [ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,\n",
" 45, 45, 45, 45, 45, 45],\n",
" [ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,\n",
" 60, 60, 60, 60, 60, 60],\n",
" [ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,\n",
" 75, 75, 75, 75, 75, 75],\n",
" [ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,\n",
" 90, 90, 90, 90, 90, 90]])</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-4523da80-b786-49bd-8a85-a6dc1cbbf9a2' class='xr-section-summary-in' type='checkbox' checked><label for='section-4523da80-b786-49bd-8a85-a6dc1cbbf9a2' class='xr-section-summary' >Data variables: <span>(1)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><ul class='xr-var-list'><li class='xr-var-item'><div class='xr-var-name'><span>data</span></div><div class='xr-var-dims'>(y, x)</div><div class='xr-var-dtype'>float64</div><div class='xr-var-preview xr-preview'>2.016 2.009 1.997 ... 2.009 2.016</div><input id='attrs-515f20ef-94bf-4398-87e1-54278df5f164' class='xr-var-attrs-in' type='checkbox' disabled><label for='attrs-515f20ef-94bf-4398-87e1-54278df5f164' title='Show/Hide attributes'><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg></label><input id='data-1f148ea4-743f-4add-9af9-e1e049b2e58d' class='xr-var-data-in' type='checkbox'><label for='data-1f148ea4-743f-4add-9af9-e1e049b2e58d' title='Show/Hide data repr'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg></label><div class='xr-var-attrs'><dl class='xr-attrs'></dl></div><div class='xr-var-data'><pre>array([[2.01600962, 2.00851854, 1.99704154, 1.98694883, 1.98296291,\n",
" 1.98694883, 1.99704154, 2.00851854, 2.01600962, 2.01600962,\n",
" 2.00851854, 1.99704154, 1.98694883, 1.98296291, 1.98694883,\n",
" 1.99704154, 2.00851854, 2.01600962],\n",
" [2.1376148 , 2.0732233 , 1.97456981, 1.88781539, 1.85355339,\n",
" 1.88781539, 1.97456981, 2.0732233 , 2.1376148 , 2.1376148 ,\n",
" 2.0732233 , 1.97456981, 1.88781539, 1.85355339, 1.88781539,\n",
" 1.97456981, 2.0732233 , 2.1376148 ],\n",
" [2.34824114, 2.18529524, 1.93564764, 1.71611122, 1.62940952,\n",
" 1.71611122, 1.93564764, 2.18529524, 2.34824114, 2.34824114,\n",
" 2.18529524, 1.93564764, 1.71611122, 1.62940952, 1.71611122,\n",
" 1.93564764, 2.18529524, 2.34824114],\n",
" [2.59145148, 2.31470476, 1.89070418, 1.51784433, 1.37059048,\n",
" 1.51784433, 1.89070418, 2.31470476, 2.59145148, 2.59145148,\n",
" 2.31470476, 1.89070418, 1.51784433, 1.37059048, 1.51784433,\n",
" 1.89070418, 2.31470476, 2.59145148],\n",
" [2.80207782, 2.4267767 , 1.85178201, 1.34614017, 1.14644661,\n",
" 1.34614017, 1.85178201, 2.4267767 , 2.80207782, 2.80207782,\n",
" 2.4267767 , 1.85178201, 1.34614017, 1.14644661, 1.34614017,\n",
" 1.85178201, 2.4267767 , 2.80207782],\n",
"...\n",
" [2.80207782, 2.4267767 , 1.85178201, 1.34614017, 1.14644661,\n",
" 1.34614017, 1.85178201, 2.4267767 , 2.80207782, 2.80207782,\n",
" 2.4267767 , 1.85178201, 1.34614017, 1.14644661, 1.34614017,\n",
" 1.85178201, 2.4267767 , 2.80207782],\n",
" [2.59145148, 2.31470476, 1.89070418, 1.51784433, 1.37059048,\n",
" 1.51784433, 1.89070418, 2.31470476, 2.59145148, 2.59145148,\n",
" 2.31470476, 1.89070418, 1.51784433, 1.37059048, 1.51784433,\n",
" 1.89070418, 2.31470476, 2.59145148],\n",
" [2.34824114, 2.18529524, 1.93564764, 1.71611122, 1.62940952,\n",
" 1.71611122, 1.93564764, 2.18529524, 2.34824114, 2.34824114,\n",
" 2.18529524, 1.93564764, 1.71611122, 1.62940952, 1.71611122,\n",
" 1.93564764, 2.18529524, 2.34824114],\n",
" [2.1376148 , 2.0732233 , 1.97456981, 1.88781539, 1.85355339,\n",
" 1.88781539, 1.97456981, 2.0732233 , 2.1376148 , 2.1376148 ,\n",
" 2.0732233 , 1.97456981, 1.88781539, 1.85355339, 1.88781539,\n",
" 1.97456981, 2.0732233 , 2.1376148 ],\n",
" [2.01600962, 2.00851854, 1.99704154, 1.98694883, 1.98296291,\n",
" 1.98694883, 1.99704154, 2.00851854, 2.01600962, 2.01600962,\n",
" 2.00851854, 1.99704154, 1.98694883, 1.98296291, 1.98694883,\n",
" 1.99704154, 2.00851854, 2.01600962]])</pre></div></li></ul></div></li><li class='xr-section-item'><input id='section-b89f715e-4bb8-4f5f-b58e-b4483619f331' class='xr-section-summary-in' type='checkbox' disabled ><label for='section-b89f715e-4bb8-4f5f-b58e-b4483619f331' class='xr-section-summary' title='Expand/collapse section'>Attributes: <span>(0)</span></label><div class='xr-section-inline-details'></div><div class='xr-section-details'><dl class='xr-attrs'></dl></div></li></ul></div></div>"
],
"text/plain": [
"<xarray.Dataset>\n",
"Dimensions: (y: 12, x: 18, y_b: 13, x_b: 19)\n",
"Coordinates:\n",
" lon (y, x) float64 -170.0 -150.0 -130.0 -110.0 ... 130.0 150.0 170.0\n",
" lat (y, x) float64 -82.5 -82.5 -82.5 -82.5 ... 82.5 82.5 82.5 82.5\n",
" lon_b (y_b, x_b) int64 -180 -160 -140 -120 -100 ... 100 120 140 160 180\n",
" lat_b (y_b, x_b) int64 -90 -90 -90 -90 -90 -90 -90 ... 90 90 90 90 90 90\n",
"Dimensions without coordinates: y, x, y_b, x_b\n",
"Data variables:\n",
" data (y, x) float64 2.016 2.009 1.997 1.987 ... 1.987 1.997 2.009 2.016"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds_in[\"data\"] = xe.data.wave_smooth(ds_in[\"lon\"], ds_in[\"lat\"])\n",
"ds_in"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.collections.QuadMesh at 0x7fcc27f6db80>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"ds_in[\"data\"].plot()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def regrid(ds_in, ds_out, dr_in, method):\n",
" \"\"\"Convenience function for one-time regridding\"\"\"\n",
" regridder = xe.Regridder(ds_in, ds_out, method, periodic=True)\n",
" dr_out = regridder(dr_in)\n",
" return dr_out"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When dealing with global grids, we need to set `periodic=True`, otherwise data\n",
"along the meridian line will be missing.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Increasing resolution\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"bilinear\n",
"CPU times: user 386 ms, sys: 24.9 ms, total: 410 ms\n",
"Wall time: 408 ms\n",
"\n",
"conservative\n",
"CPU times: user 66.8 ms, sys: 3.79 ms, total: 70.6 ms\n",
"Wall time: 70.4 ms\n",
"\n",
"conservative_normed\n",
"CPU times: user 84.6 ms, sys: 266 µs, total: 84.9 ms\n",
"Wall time: 84.6 ms\n",
"\n",
"nearest_s2d\n",
"CPU times: user 29.6 ms, sys: 0 ns, total: 29.6 ms\n",
"Wall time: 29.4 ms\n",
"\n",
"nearest_d2s\n",
"CPU times: user 8.44 ms, sys: 0 ns, total: 8.44 ms\n",
"Wall time: 8.22 ms\n",
"\n",
"patch\n",
"CPU times: user 420 ms, sys: 12.3 ms, total: 432 ms\n",
"Wall time: 431 ms\n",
"\n"
]
}
],
"source": [
"for method in method_list:\n",
" print(method)\n",
" %time ds_fine[method] = regrid(ds_in, ds_fine, ds_in['data'], method)\n",
" print('')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nearest neighbour algorithms are very fast while the patch method is quite slow.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 576x576 with 12 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(3, 2, figsize=[8, 8])\n",
"\n",
"for i, method in enumerate(method_list):\n",
" ax = axes.flatten()[i]\n",
" ds_fine[method].plot.pcolormesh(ax=ax)\n",
" ax.set_title(method, fontsize=15)\n",
"\n",
"plt.tight_layout()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When regridding from low-resolution to high-resolution, `bilinear` and `patch`\n",
"will produce smooth results, while `conservative` and `nearest_s2d` will\n",
"preserve the original coarse grid structure (although the data is now defined on\n",
"a finer grid.).\n",
"\n",
"`nearest_d2s` is quite different from others: One source point can be mapped to\n",
"**only one destination point**. Because we have far less source points (on a\n",
"low-resolution grid) than destination points (on a high-resolution grid), most\n",
"destination points cannot receive any data so they just have zero values. Only\n",
"the destination points that are closest to source points can receive data.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Decreasing resolution\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"for method in method_list:\n",
" ds_coarse[method] = regrid(ds_in, ds_coarse, ds_in[\"data\"], method)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
gitextract_0jcmuyrd/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yaml
│ ├── linting.yaml
│ └── pypi.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── .prettierrc.toml
├── CHANGES.rst
├── LICENSE
├── MANIFEST.in
├── README.rst
├── binder/
│ └── environment.yml
├── ci/
│ ├── doc.yml
│ ├── environment-upstream-dev.yml
│ └── environment.yml
├── codecov.yml
├── doc/
│ ├── Makefile
│ ├── changes.rst
│ ├── conf.py
│ ├── index.rst
│ ├── installation.rst
│ ├── internal_api.rst
│ ├── large_problems_on_HPC.rst
│ ├── limitations.rst
│ ├── make.bat
│ ├── notebooks/
│ │ ├── Backend.ipynb
│ │ ├── Compare_algorithms.ipynb
│ │ ├── Curvilinear_grid.ipynb
│ │ ├── Dask.ipynb
│ │ ├── Dataset.ipynb
│ │ ├── Masking.ipynb
│ │ ├── Pure_numpy.ipynb
│ │ ├── Rectilinear_grid.ipynb
│ │ ├── Reuse_regridder.ipynb
│ │ ├── Spatial_Averaging.ipynb
│ │ └── Using_LocStream.ipynb
│ ├── other_tools.rst
│ ├── releases.rst
│ ├── requirements.txt
│ ├── user_api.rst
│ └── why.rst
├── pyproject.toml
├── readthedocs.yml
├── requirements.txt
├── setup.cfg
└── xesmf/
├── __init__.py
├── backend.py
├── data.py
├── frontend.py
├── smm.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_backend.py
│ ├── test_frontend.py
│ ├── test_oceanmodels.py
│ ├── test_smm.py
│ └── test_util.py
└── util.py
SYMBOL INDEX (160 symbols across 11 files)
FILE: xesmf/backend.py
function warn_f_contiguous (line 30) | def warn_f_contiguous(a):
function warn_lat_range (line 45) | def warn_lat_range(lat):
class Grid (line 60) | class Grid(ESMF.Grid):
method from_xarray (line 62) | def from_xarray(cls, lon, lat, periodic=False, mask=None):
method get_shape (line 148) | def get_shape(self, loc=ESMF.StaggerLoc.CENTER):
class LocStream (line 154) | class LocStream(ESMF.LocStream):
method from_xarray (line 156) | def from_xarray(cls, lon, lat):
method get_shape (line 186) | def get_shape(self):
function add_corner (line 191) | def add_corner(grid, lon_b, lat_b):
class Mesh (line 233) | class Mesh(ESMF.Mesh):
method from_polygons (line 235) | def from_polygons(cls, polys, element_coords='centroid'):
method get_shape (line 312) | def get_shape(self, loc=ESMF.MeshLoc.ELEMENT):
function esmf_regrid_build (line 317) | def esmf_regrid_build( # noqa: C901
function esmf_regrid_apply (line 541) | def esmf_regrid_apply(regrid, indata):
function esmf_regrid_finalize (line 589) | def esmf_regrid_finalize(regrid):
function esmf_locstream (line 615) | def esmf_locstream(lon, lat):
function esmf_grid (line 623) | def esmf_grid(lon, lat, periodic=False, mask=None):
FILE: xesmf/data.py
function wave_smooth (line 8) | def wave_smooth(lon, lat):
FILE: xesmf/frontend.py
function subset_regridder (line 42) | def subset_regridder(
function as_2d_mesh (line 58) | def as_2d_mesh(lon, lat):
function _get_lon_lat (line 69) | def _get_lon_lat(ds):
function _get_lon_lat_bounds (line 86) | def _get_lon_lat_bounds(ds):
function ds_to_ESMFgrid (line 115) | def ds_to_ESMFgrid(ds, need_bounds=False, periodic=None, append=None):
function ds_to_ESMFlocstream (line 173) | def ds_to_ESMFlocstream(ds):
function polys_to_ESMFmesh (line 207) | def polys_to_ESMFmesh(polys):
class BaseRegridder (line 233) | class BaseRegridder(object):
method __init__ (line 234) | def __init__(
method A (line 479) | def A(self):
method w (line 492) | def w(self) -> xr.DataArray:
method _get_default_filename (line 505) | def _get_default_filename(self):
method _compute_weights (line 522) | def _compute_weights(self, grid_in, grid_out):
method __call__ (line 538) | def __call__(self, indata, keep_attrs=False, skipna=False, na_thres=1....
method _regrid (line 644) | def _regrid(indata, weights, *, shape_in, shape_out, skipna, na_thres):
method regrid_array (line 663) | def regrid_array(self, indata, weights, skipna=False, na_thres=1.0, ou...
method regrid_numpy (line 724) | def regrid_numpy(self, indata, **kwargs):
method regrid_dask (line 731) | def regrid_dask(self, indata, **kwargs):
method regrid_dataarray (line 738) | def regrid_dataarray(
method regrid_dataset (line 758) | def regrid_dataset(
method _parse_xrinput (line 788) | def _parse_xrinput(self, dr_in):
method _format_xroutput (line 823) | def _format_xroutput(self, out, new_dims=None):
method __repr__ (line 827) | def __repr__(self):
method to_netcdf (line 847) | def to_netcdf(self, filename=None):
class Regridder (line 877) | class Regridder(BaseRegridder):
method __init__ (line 878) | def __init__(
method _init_para_regrid (line 1144) | def _init_para_regrid(self, ds_in, ds_out, kwargs):
method _format_xroutput (line 1261) | def _format_xroutput(self, out, new_dims=None):
class SpatialAverager (line 1275) | class SpatialAverager(BaseRegridder):
method __init__ (line 1276) | def __init__(
method _check_polys_length (line 1412) | def _check_polys_length(polys, threshold=1):
method _compute_weights_and_area (line 1428) | def _compute_weights_and_area(self, grid_in, mesh_out):
method _compute_weights (line 1449) | def _compute_weights(self, grid_in, grid_out):
method w (line 1499) | def w(self) -> xr.DataArray:
method _get_default_filename (line 1511) | def _get_default_filename(self):
method __repr__ (line 1519) | def __repr__(self):
method _format_xroutput (line 1532) | def _format_xroutput(self, out, new_dims=None):
FILE: xesmf/smm.py
function read_weights (line 14) | def read_weights(weights, n_in, n_out):
function _parse_coords_and_values (line 53) | def _parse_coords_and_values(indata, n_in, n_out):
function check_shapes (line 104) | def check_shapes(indata, weights, shape_in, shape_out):
function apply_weights (line 159) | def apply_weights(weights, indata, shape_in, shape_out):
function post_apply_target_mask_to_weights (line 216) | def post_apply_target_mask_to_weights(weights, target_mask_2d):
function add_nans_to_weights (line 270) | def add_nans_to_weights(weights):
function mask_source_indices (line 315) | def mask_source_indices(weights, source_indices_to_mask):
function gen_mask_from_weights (line 367) | def gen_mask_from_weights(weights, nlat, nlon):
function _combine_weight_multipoly (line 399) | def _combine_weight_multipoly(weights, areas, indexes):
FILE: xesmf/tests/conftest.py
function threaded_scheduler (line 6) | def threaded_scheduler():
function processes_scheduler (line 12) | def processes_scheduler():
function distributed_scheduler (line 18) | def distributed_scheduler():
function pytest_addoption (line 30) | def pytest_addoption(parser):
function pytest_configure (line 34) | def pytest_configure(config):
function pytest_collection_modifyitems (line 38) | def pytest_collection_modifyitems(config, items):
FILE: xesmf/tests/test_backend.py
function test_warn_f_on_array (line 54) | def test_warn_f_on_array():
function test_warn_f_on_grid (line 60) | def test_warn_f_on_grid():
function test_warn_lat_range (line 66) | def test_warn_lat_range():
function test_esmf_grid_with_corner (line 75) | def test_esmf_grid_with_corner():
function test_esmf_build_bilinear (line 108) | def test_esmf_build_bilinear():
function test_esmf_extrapolation (line 123) | def test_esmf_extrapolation():
function test_esmf_extrapolation_creep_fill (line 145) | def test_esmf_extrapolation_creep_fill():
function test_regrid (line 172) | def test_regrid():
function test_regrid_periodic_wrong (line 227) | def test_regrid_periodic_wrong():
function test_regrid_periodic_correct (line 245) | def test_regrid_periodic_correct():
function test_esmf_locstream (line 262) | def test_esmf_locstream():
function test_read_weights (line 282) | def test_read_weights(tmp_path):
function test_vector_regrid (line 325) | def test_vector_regrid():
function test_deprecated (line 355) | def test_deprecated():
FILE: xesmf/tests/test_frontend.py
function _segmentize (line 102) | def _segmentize(p):
function test_as_2d_mesh (line 112) | def test_as_2d_mesh():
function test_build_regridder (line 159) | def test_build_regridder(method, locstream_in, locstream_out, unmapped_t...
function test_regridder_creep_fill_validation (line 173) | def test_regridder_creep_fill_validation():
function test_existing_weights (line 192) | def test_existing_weights():
function test_regridder_w (line 224) | def test_regridder_w():
function test_to_netcdf (line 249) | def test_to_netcdf(tmp_path, unmapped_to_nan):
function test_conservative_without_bounds (line 296) | def test_conservative_without_bounds():
function test_regridder_from_dict (line 301) | def test_regridder_from_dict():
function test_regrid_periodic_wrong (line 311) | def test_regrid_periodic_wrong():
function test_regrid_periodic_correct (line 322) | def test_regrid_periodic_correct():
function ds_2d_to_1d (line 332) | def ds_2d_to_1d(ds):
function test_regridded_respects_input_dtype (line 350) | def test_regridded_respects_input_dtype(dtype, data_in):
function test_regrid_with_1d_grid (line 363) | def test_regrid_with_1d_grid():
function test_regrid_with_1d_grid_infer_bounds (line 380) | def test_regrid_with_1d_grid_infer_bounds():
function test_regrid_cfbounds (line 394) | def test_regrid_cfbounds():
function test_regrid_dataarray (line 414) | def test_regrid_dataarray(use_cfxr):
function test_regrid_dataarray_endianess (line 467) | def test_regrid_dataarray_endianess(use_dask):
function test_regrid_from_dataarray (line 486) | def test_regrid_from_dataarray():
function test_regrid_dataarray_to_locstream (line 491) | def test_regrid_dataarray_to_locstream():
function test_regrid_dataarray_from_locstream (line 508) | def test_regrid_dataarray_from_locstream():
function test_regrid_dask (line 531) | def test_regrid_dask(request, scheduler):
function test_regrid_dask_to_locstream (line 585) | def test_regrid_dask_to_locstream(request, scheduler):
function test_regrid_dask_from_locstream (line 597) | def test_regrid_dask_from_locstream(request, scheduler):
function test_regrid_dataarray_dask (line 608) | def test_regrid_dataarray_dask(request, scheduler):
function test_regrid_dataarray_dask_to_locstream (line 630) | def test_regrid_dataarray_dask_to_locstream(request, scheduler):
function test_regrid_dataarray_dask_from_locstream (line 641) | def test_regrid_dataarray_dask_from_locstream(request, scheduler):
function test_dask_output_chunks (line 651) | def test_dask_output_chunks():
function test_para_weight_gen (line 681) | def test_para_weight_gen():
function test_para_weight_gen_errors (line 719) | def test_para_weight_gen_errors():
function test_regrid_dataset (line 724) | def test_regrid_dataset():
function test_regrid_dataset_extracoords (line 760) | def test_regrid_dataset_extracoords():
function test_regrid_dataset_dask (line 785) | def test_regrid_dataset_dask(request, scheduler):
function test_regrid_dataset_to_locstream (line 805) | def test_regrid_dataset_to_locstream():
function test_build_regridder_with_masks (line 813) | def test_build_regridder_with_masks(transpose):
function test_regrid_dataset_from_locstream (line 835) | def test_regrid_dataset_from_locstream():
function test_ds_to_ESMFlocstream (line 842) | def test_ds_to_ESMFlocstream():
function test_spatial_averager (line 867) | def test_spatial_averager(poly, exp, use_dask):
function test_spatial_averager_warns (line 881) | def test_spatial_averager_warns():
function test_spatial_averager_with_zonal_region (line 886) | def test_spatial_averager_with_zonal_region():
function test_compare_weights_from_poly_and_grid (line 908) | def test_compare_weights_from_poly_and_grid():
function test_polys_to_ESMFmesh (line 947) | def test_polys_to_ESMFmesh():
function test_skipna (line 980) | def test_skipna(method, skipna, na_thres, nvalid):
function test_non_cf_latlon (line 988) | def test_non_cf_latlon():
function test_locstream_dim_name (line 1005) | def test_locstream_dim_name(var_renamer, dim_out):
function test_spatial_averager_mask (line 1020) | def test_spatial_averager_mask():
function test_post_mask_source (line 1040) | def test_post_mask_source():
function test_post_mask_source_exceptions (line 1068) | def test_post_mask_source_exceptions():
function test_post_mask_source_parallel_mode (line 1103) | def test_post_mask_source_parallel_mode():
function test_locstream_input_grid_output_with_target_mask_applied (line 1142) | def test_locstream_input_grid_output_with_target_mask_applied():
function test_input_output_dims (line 1175) | def test_input_output_dims():
FILE: xesmf/tests/test_oceanmodels.py
function test_mom6like_to_5x5 (line 62) | def test_mom6like_to_5x5():
FILE: xesmf/tests/test_smm.py
function test_add_nans_to_weights (line 9) | def test_add_nans_to_weights():
function test_mask_source_indices (line 33) | def test_mask_source_indices():
function test_gen_mask_from_weights (line 51) | def test_gen_mask_from_weights():
function test_post_apply_target_mask_to_weights (line 71) | def test_post_apply_target_mask_to_weights():
function test_post_apply_target_mask_to_weights_exceptions (line 95) | def test_post_apply_target_mask_to_weights_exceptions():
FILE: xesmf/tests/test_util.py
function test_grid_global (line 8) | def test_grid_global():
function test_grid_global_bad_resolution (line 31) | def test_grid_global_bad_resolution():
function test_cell_area (line 39) | def test_cell_area():
function test_get_edge_indices_2d (line 47) | def test_get_edge_indices_2d():
function test_simple_tripolar_grid (line 60) | def test_simple_tripolar_grid():
FILE: xesmf/util.py
function _grid_1d (line 16) | def _grid_1d(start_b, end_b, step):
function grid_2d (line 41) | def grid_2d(lon0_b, lon1_b, d_lon, lat0_b, lat1_b, d_lat):
function cf_grid_2d (line 83) | def cf_grid_2d(lon0_b, lon1_b, d_lon, lat0_b, lat1_b, d_lat):
function grid_global (line 132) | def grid_global(d_lon, d_lat, cf=False, lon1=180):
function _flatten_poly_list (line 173) | def _flatten_poly_list(polys):
function split_polygons_and_holes (line 183) | def split_polygons_and_holes(polys):
function simple_tripolar_grid (line 223) | def simple_tripolar_grid(nlons, nlats, lat_cap=60, lon_cut=-300):
function _bipolar_projection (line 263) | def _bipolar_projection(lamg, phig, lon_bp, rp, metrics_only=False):
function _generate_bipolar_cap_mesh (line 333) | def _generate_bipolar_cap_mesh(Ni, Nj_ncap, lat0_bp, lon_bp, ensure_nj_e...
function _mdist (line 355) | def _mdist(x1, x2):
function cell_area (line 363) | def cell_area(ds, earth_radius=None):
function _get_edge_indices_2d (line 410) | def _get_edge_indices_2d(nlons, nlats):
function _unname_dataset (line 420) | def _unname_dataset(ds, sequence, dims, suffix):
function _rename_dataset (line 445) | def _rename_dataset(ds, sequence, dims, suffix):
Condensed preview — 58 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,711K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 246,
"preview": "version: 2\nupdates:\n # - package-ecosystem: pip\n # directory: \"/\"\n # schedule:\n # interval: daily\n - packag"
},
{
"path": ".github/workflows/ci.yaml",
"chars": 2739,
"preview": "name: CI\n\non:\n push:\n branches:\n - master\n pull_request:\n branches:\n - \"*\"\n schedule:\n - cron: \"0 "
},
{
"path": ".github/workflows/linting.yaml",
"chars": 303,
"preview": "name: linting\n\non:\n push:\n branches:\n - master\n pull_request:\n branches: \"*\"\n\njobs:\n linting:\n runs-on:"
},
{
"path": ".github/workflows/pypi.yaml",
"chars": 1305,
"preview": "name: Publish to PyPI\n\non:\n pull_request:\n push:\n branches:\n - master\n release:\n types:\n - published\n"
},
{
"path": ".gitignore",
"chars": 503,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\n"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1494,
"preview": "default_language_version:\n python: python3\n\nrepos:\n - repo: https://github.com/pre-commit/pre-commit-hooks\n rev: v6"
},
{
"path": ".prettierrc.toml",
"chars": 45,
"preview": "tabWidth = 2\nsemi = false\nsingleQuote = true\n"
},
{
"path": "CHANGES.rst",
"chars": 17471,
"preview": "What's new\n==========\n\n0.9.2 (2025-11-27)\n------------------\nThis release drops support for Python < 3.11. xESMF aims to"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2017 Jiawei Zhuang\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "MANIFEST.in",
"chars": 254,
"preview": "include LICENSE\ninclude *.rst\n\ngraft xesmf\n\nprune .github\nprune *.egg-info\nprune binder\nprune ci\nprune doc\n\nexclude *.ya"
},
{
"path": "README.rst",
"chars": 2655,
"preview": "xESMF: Universal Regridder for Geospatial Data\n==============================================\n\n|Binder| |conda| |Build S"
},
{
"path": "binder/environment.yml",
"chars": 203,
"preview": "channels:\n - conda-forge\ndependencies:\n - python=3.7\n - esmpy==7.1.0r\n - xarray\n - dask\n - numpy\n - scipy\n - sha"
},
{
"path": "ci/doc.yml",
"chars": 378,
"preview": "name: xesmf\nchannels:\n - conda-forge\ndependencies:\n # Python pin only to accelerate solving\n - python>=3.12\n - cf_xa"
},
{
"path": "ci/environment-upstream-dev.yml",
"chars": 323,
"preview": "name: xesmf\nchannels:\n - conda-forge\ndependencies:\n - cftime\n - codecov\n - dask\n - esmpy\n - netcdf4\n - numba\n - "
},
{
"path": "ci/environment.yml",
"chars": 301,
"preview": "name: xesmf\nchannels:\n - conda-forge\ndependencies:\n - python>=3.11\n - cf_xarray>=0.5.1\n - dask\n - esmpy\n - numba >"
},
{
"path": "codecov.yml",
"chars": 273,
"preview": "codecov:\n require_ci_to_pass: no\n max_report_age: off\n\ncomment: false\n\nignore:\n - \"xesmf/tests/*\"\n - \"setup.py\"\n\ncov"
},
{
"path": "doc/Makefile",
"chars": 606,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "doc/changes.rst",
"chars": 28,
"preview": ".. include:: ../CHANGES.rst\n"
},
{
"path": "doc/conf.py",
"chars": 6090,
"preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# xESMF documentation build configuration file, created by\n# sphinx-qui"
},
{
"path": "doc/index.rst",
"chars": 4523,
"preview": "xESMF: Universal Regridder for Geospatial Data\n==============================================\n\nxESMF is a Python package"
},
{
"path": "doc/installation.rst",
"chars": 4136,
"preview": ".. _installation-label:\n\nInstallation\n============\n\nTry on Binder without local installation\n---------------------------"
},
{
"path": "doc/internal_api.rst",
"chars": 203,
"preview": "Internal API\n############\n\nfrontend\n========\n\n.. automodule:: xesmf.frontend\n :members:\n\nbackend\n=======\n\n.. automodu"
},
{
"path": "doc/large_problems_on_HPC.rst",
"chars": 7338,
"preview": ".. _largeproblems-label:\n\n.. |polarstereo| image:: images/elevation_southpolarstero.png\n :width: 600\n :alt: elevation "
},
{
"path": "doc/limitations.rst",
"chars": 1572,
"preview": "Current limitations\n===================\n\n.. _irregular_meshes-label:\n\nIrregular meshes\n----------------\n\nESMPy is actual"
},
{
"path": "doc/make.bat",
"chars": 803,
"preview": "@ECHO OFF\r\n\r\npushd %~dp0\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n\tset SPHINXBUILD=py"
},
{
"path": "doc/notebooks/Backend.ipynb",
"chars": 12798,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# xESMF backend usage and benchmark"
},
{
"path": "doc/notebooks/Compare_algorithms.ipynb",
"chars": 144022,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Comparison of six regridding algo"
},
{
"path": "doc/notebooks/Curvilinear_grid.ipynb",
"chars": 880313,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Regrid between curvilinear grids\\"
},
{
"path": "doc/notebooks/Dask.ipynb",
"chars": 150301,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Lazy evaluation on Dask arrays\\n\""
},
{
"path": "doc/notebooks/Dataset.ipynb",
"chars": 141651,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Regrid xarray Dataset with multip"
},
{
"path": "doc/notebooks/Masking.ipynb",
"chars": 385340,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Masking and extrapolation in xESM"
},
{
"path": "doc/notebooks/Pure_numpy.ipynb",
"chars": 42553,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Use pure numpy array\\n\"\n ]\n },"
},
{
"path": "doc/notebooks/Rectilinear_grid.ipynb",
"chars": 229638,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Regrid between rectilinear grids\\"
},
{
"path": "doc/notebooks/Reuse_regridder.ipynb",
"chars": 170687,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Save time by reusing regridder\\n\""
},
{
"path": "doc/notebooks/Spatial_Averaging.ipynb",
"chars": 111887,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Averaging over a region\\n\",\n \""
},
{
"path": "doc/notebooks/Using_LocStream.ipynb",
"chars": 112416,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Using ESMF LocStream objects\\n\",\n"
},
{
"path": "doc/other_tools.rst",
"chars": 3555,
"preview": ".. _other_tools-label:\n\nOther geospatial regridding tools\n=================================\n\nHere is a brief overview of"
},
{
"path": "doc/releases.rst",
"chars": 704,
"preview": "Release how-to\n==============\n\nHere are the step by step instructions to release a new version of xESMF.\n\n#. Make sure :"
},
{
"path": "doc/requirements.txt",
"chars": 111,
"preview": "numpydoc\ngeopandas\ndescartes\nipython\nPygments>=2.6\nnbsphinx\nsphinx<7\nsphinx_rtd_theme\ncf_xarray\ndocutils!=0.18\n"
},
{
"path": "doc/user_api.rst",
"chars": 344,
"preview": "User API\n########\n\nRegridder\n=========\n\n.. autoclass:: xesmf.frontend.Regridder\n :inherited-members:\n :special-mem"
},
{
"path": "doc/why.rst",
"chars": 2556,
"preview": "Why invent a new regridding package?\n====================================\n\nFor scientific correctness\n------------------"
},
{
"path": "pyproject.toml",
"chars": 1993,
"preview": "[build-system]\nbuild-backend = \"setuptools.build_meta\"\nrequires = [\n \"setuptools>=41.2\",\n \"setuptools-scm\",\n \"wheel\","
},
{
"path": "readthedocs.yml",
"chars": 431,
"preview": "version: 2\n\nbuild:\n os: \"ubuntu-24.04\"\n tools:\n python: \"mambaforge-23.11\"\n jobs:\n pre_install:\n - conda l"
},
{
"path": "requirements.txt",
"chars": 146,
"preview": "cf-xarray>=0.5.1\n# We cannot list this here b/c it is not on PyPI.\n#esmpy>=8.0.0\nnumba >=0.55.2\nnumpy>=1.16\nshapely\nspa"
},
{
"path": "setup.cfg",
"chars": 184,
"preview": "[bumpversion]\ncurrent_version = 0.6.2\n\n[flake8]\nexclude = doc\nignore =\nmax-line-length = 100\nmax-complexity = 18\nselect "
},
{
"path": "xesmf/__init__.py",
"chars": 182,
"preview": "# flake8: noqa\n\nfrom . import data, util\nfrom .frontend import Regridder, SpatialAverager\n\ntry:\n from ._version impor"
},
{
"path": "xesmf/backend.py",
"chars": 22765,
"preview": "\"\"\"\nBackend for xESMF. This module wraps ESMPy's complicated API and can create\nESMF Grid and Regrid objects only using "
},
{
"path": "xesmf/data.py",
"chars": 1109,
"preview": "\"\"\"\nStandard test data for regridding benchmark.\n\"\"\"\n\nimport numpy as np\n\n\ndef wave_smooth(lon, lat):\n r\"\"\"\n Spher"
},
{
"path": "xesmf/frontend.py",
"chars": 63001,
"preview": "\"\"\"\nFrontend for xESMF, exposed to users.\n\"\"\"\n\nimport warnings\n\nimport cf_xarray as cfxr\nimport numpy as np\nimport spars"
},
{
"path": "xesmf/smm.py",
"chars": 16332,
"preview": "\"\"\"\nSparse matrix multiplication (SMM) using scipy.sparse library.\n\"\"\"\n\nimport warnings\nfrom pathlib import Path\n\nimport"
},
{
"path": "xesmf/tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "xesmf/tests/conftest.py",
"chars": 1175,
"preview": "import dask\nimport pytest\n\n\n@pytest.fixture(scope='function')\ndef threaded_scheduler():\n with dask.config.set(schedul"
},
{
"path": "xesmf/tests/test_backend.py",
"chars": 12431,
"preview": "import os\n\ntry:\n import esmpy as ESMF\nexcept ImportError:\n import ESMF\n\nimport numpy as np\nimport pytest\nimport xa"
},
{
"path": "xesmf/tests/test_frontend.py",
"chars": 43055,
"preview": "import os\nimport warnings\n\nimport cf_xarray as cfxr\nimport dask\nimport numpy as np\nimport pytest\nimport xarray as xr\nfro"
},
{
"path": "xesmf/tests/test_oceanmodels.py",
"chars": 2461,
"preview": "import cftime\nimport numpy as np\nimport pytest\nimport xarray as xr\n\nimport xesmf\n\nmom6like = xr.Dataset(\n data_vars=d"
},
{
"path": "xesmf/tests/test_smm.py",
"chars": 4785,
"preview": "import numpy as np\nimport pytest\nimport sparse as sps\nimport xarray as xr\n\nimport xesmf as xe\n\n\ndef test_add_nans_to_wei"
},
{
"path": "xesmf/tests/test_util.py",
"chars": 2001,
"preview": "import numpy as np\nimport pytest\nfrom numpy.testing import assert_almost_equal\n\nimport xesmf as xe\n\n\ndef test_grid_globa"
},
{
"path": "xesmf/util.py",
"chars": 14511,
"preview": "import warnings\n\nimport numpy as np\nimport xarray as xr\nfrom shapely.geometry import MultiPolygon, Polygon\n\ntry:\n imp"
}
]
About this extraction
This page contains the full source code of the pangeo-data/xESMF GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 58 files (2.5 MB), approximately 660.1k tokens, and a symbol index with 160 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.