From e28e846cd7a6deea87c26c0d1d101bc52b5c4f6e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 17 Apr 2024 20:21:51 +0800 Subject: [PATCH 01/17] Pass GMT_GRID virtual file to GMT C API --- doc/api/index.rst | 1 + pygmt/clib/session.py | 56 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/doc/api/index.rst b/doc/api/index.rst index 646fb49886a..4d369c4dfd5 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -319,3 +319,4 @@ Low level access (these are mostly used by the :mod:`pygmt.clib` package): clib.Session.virtualfile_from_grid clib.Session.virtualfile_from_matrix clib.Session.virtualfile_from_vectors + clib.Session.virtualfile_from_xrgrid diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 46bce82d692..0d8a32f9fba 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -26,6 +26,7 @@ ) from pygmt.clib.loading import load_libgmt from pygmt.datatypes import _GMT_DATASET, _GMT_GRID +from pygmt.datatypes.header import gmt_grdfloat from pygmt.exceptions import ( GMTCLibError, GMTCLibNoSessionError, @@ -325,6 +326,22 @@ def get_libgmt_func(self, name, argtypes=None, restype=None): function.restype = restype return function + def set_allocmode(self, family, obj): + """ + Set allocation mode of object to external. + """ + c_set_allocmode = self.get_libgmt_func( + "GMT_Set_AllocMode", + argtypes=[ctp.c_void_p, ctp.c_uint, ctp.c_void_p], + restype=ctp.c_void_p, + ) + family_int = self._parse_constant(family, valid=FAMILIES, valid_modifiers=VIAS) + status = c_set_allocmode(self.session_pointer, family_int, obj) + if status: + raise GMTCLibError( + f"Failed to set allocation mode of object to external:\n{self._error_message}" + ) + def create(self, name): """ Create a new GMT C API session. @@ -1597,7 +1614,7 @@ def virtualfile_in( # noqa: PLR0912 "file": contextlib.nullcontext, "arg": contextlib.nullcontext, "geojson": tempfile_from_geojson, - "grid": self.virtualfile_from_grid, + "grid": self.virtualfile_from_xrgrid, "image": tempfile_from_image, # Note: virtualfile_from_matrix is not used because a matrix can be # converted to vectors instead, and using vectors allows for better @@ -1839,6 +1856,43 @@ def read_virtualfile( dtype = {"dataset": _GMT_DATASET, "grid": _GMT_GRID}[kind] return ctp.cast(pointer, ctp.POINTER(dtype)) + @contextlib.contextmanager + def virtualfile_from_xrgrid(self, xrgrid): + """ + Create a virtual file from an xarray.DataArray object. + """ + family = "GMT_IS_GRID" + geometry = "GMT_IS_SURFACE" + matrix, region, inc = dataarray_to_matrix(xrgrid) + + _gtype = {0: "GMT_GRID_IS_CARTESIAN", 1: "GMT_GRID_IS_GEO"}[xrgrid.gmt.gtype] + _reg = {0: "GMT_GRID_NODE_REG", 1: "GMT_GRID_PIXEL_REG"}[ + xrgrid.gmt.registration + ] + + data = self.create_data( + family, + geometry, + mode=f"GMT_CONTAINER_ONLY|{_gtype}", + ranges=region, + inc=inc, + registration=_reg, + pad=self["GMT_PAD_DEFAULT"], + ) + if Version(self._info["version"]) < Version("6.5.0"): + # Upstream bug fixed in GMT>=6.5.0 + self.set_allocmode(family, data) + + gmtgrid = ctp.cast(data, ctp.POINTER(_GMT_GRID)) + header = gmtgrid.contents.header.contents + header.z_min, header.z_max = matrix.min(), matrix.max() + + matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) + gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) + + with self.open_virtualfile(family, geometry, "GMT_IN", gmtgrid) as vfile: + yield vfile + def virtualfile_to_dataset( self, vfname: str, From b0b3eec5598025bc8f766e9d70047b37d9ae4fa8 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 24 Jun 2024 19:12:57 +0800 Subject: [PATCH 02/17] Test GMT's grdinfo-L branch --- .github/workflows/ci_tests_dev.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests_dev.yaml b/.github/workflows/ci_tests_dev.yaml index 7cc17a559d7..70fef8961f9 100644 --- a/.github/workflows/ci_tests_dev.yaml +++ b/.github/workflows/ci_tests_dev.yaml @@ -37,7 +37,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-24.04, macos-14, windows-2022] - gmt_git_ref: [master] + gmt_git_ref: [grdinfo-L] timeout-minutes: 30 defaults: run: From 39d39d4cdb46ee3f0087a5680331fde5f24e2443 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 24 Jun 2024 22:34:56 +0800 Subject: [PATCH 03/17] Revert "Test GMT's grdinfo-L branch" This reverts commit b0b3eec5598025bc8f766e9d70047b37d9ae4fa8. --- .github/workflows/ci_tests_dev.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests_dev.yaml b/.github/workflows/ci_tests_dev.yaml index 70fef8961f9..7cc17a559d7 100644 --- a/.github/workflows/ci_tests_dev.yaml +++ b/.github/workflows/ci_tests_dev.yaml @@ -37,7 +37,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-24.04, macos-14, windows-2022] - gmt_git_ref: [grdinfo-L] + gmt_git_ref: [master] timeout-minutes: 30 defaults: run: From ce1af4fdd3ec2c2c1eece972725f2960b1aeafe1 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 25 Jun 2024 11:10:41 +0800 Subject: [PATCH 04/17] Try pad=0 --- pygmt/clib/session.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 94a276c8ac3..1102f266bed 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1892,7 +1892,8 @@ def virtualfile_from_xrgrid(self, xrgrid): ranges=region, inc=inc, registration=_reg, - pad=self["GMT_PAD_DEFAULT"], + #pad=self["GMT_PAD_DEFAULT"], + pad=0, ) if Version(self._info["version"]) < Version("6.5.0"): # Upstream bug fixed in GMT>=6.5.0 @@ -1902,7 +1903,7 @@ def virtualfile_from_xrgrid(self, xrgrid): header = gmtgrid.contents.header.contents header.z_min, header.z_max = matrix.min(), matrix.max() - matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) + #matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) with self.open_virtualfile(family, geometry, "GMT_IN", gmtgrid) as vfile: From 173ade7832c996d9a20bf5ab6b7a3d190d5a6886 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 25 Jun 2024 11:19:47 +0800 Subject: [PATCH 05/17] Revert "Try pad=0" This reverts commit ce1af4fdd3ec2c2c1eece972725f2960b1aeafe1. --- pygmt/clib/session.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 1102f266bed..94a276c8ac3 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1892,8 +1892,7 @@ def virtualfile_from_xrgrid(self, xrgrid): ranges=region, inc=inc, registration=_reg, - #pad=self["GMT_PAD_DEFAULT"], - pad=0, + pad=self["GMT_PAD_DEFAULT"], ) if Version(self._info["version"]) < Version("6.5.0"): # Upstream bug fixed in GMT>=6.5.0 @@ -1903,7 +1902,7 @@ def virtualfile_from_xrgrid(self, xrgrid): header = gmtgrid.contents.header.contents header.z_min, header.z_max = matrix.min(), matrix.max() - #matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) + matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) with self.open_virtualfile(family, geometry, "GMT_IN", gmtgrid) as vfile: From 5fc4a205d01c61202b113e0eee3cb0152e9ee1db Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 16:20:47 +0800 Subject: [PATCH 06/17] Fix the expected result for grdsample --- pygmt/tests/test_grdsample.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pygmt/tests/test_grdsample.py b/pygmt/tests/test_grdsample.py index 11812a1226a..f75282a9e62 100644 --- a/pygmt/tests/test_grdsample.py +++ b/pygmt/tests/test_grdsample.py @@ -47,11 +47,11 @@ def fixture_expected_grid(): """ return xr.DataArray( data=[ - [460.84375, 482.78125, 891.09375], - [680.46875, 519.09375, 764.9375], - [867.75, 579.03125, 852.53125], - [551.75, 666.6875, 958.21875], - [411.3125, 518.4375, 931.28125], + [460.84375, 482.78125, 848.6875], + [680.46875, 519.09375, 760.84375], + [867.75, 579.03125, 804.875], + [551.75, 666.6875, 934.09375], + [411.3125, 518.4375, 879.875], ], coords={ "lon": [-52, -50, -48], From c8f31c9ecbe860b3b740c3e08aa3c351726227ab Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 16:36:44 +0800 Subject: [PATCH 07/17] Add an internal parameter to make grdsample work --- pygmt/clib/session.py | 9 ++++++--- pygmt/src/grdsample.py | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index fccdfdb5920..ef55a78de44 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1554,6 +1554,7 @@ def virtualfile_in( # noqa: PLR0912 extra_arrays=None, required_z=False, required_data=True, + _grid_mode="GMT_IN", # An internal parameter to workaround GMT API bugs. ): """ Store any data inside a virtual file. @@ -1638,7 +1639,7 @@ def virtualfile_in( # noqa: PLR0912 }[kind] # Ensure the data is an iterable (Python list or tuple) - if kind in {"geojson", "grid", "image", "file", "arg"}: + if kind in {"geojson", "image", "file", "arg"}: if kind == "image" and data.dtype != "uint8": msg = ( f"Input image has dtype: {data.dtype} which is unsupported, " @@ -1649,6 +1650,8 @@ def virtualfile_in( # noqa: PLR0912 ) warnings.warn(message=msg, category=RuntimeWarning, stacklevel=2) _data = (data,) if not isinstance(data, pathlib.PurePath) else (str(data),) + elif kind == "grid": + _data = (data, _grid_mode) elif kind == "vectors": _data = [np.atleast_1d(x), np.atleast_1d(y)] if z is not None: @@ -1873,7 +1876,7 @@ def read_virtualfile( return ctp.cast(pointer, ctp.POINTER(dtype)) @contextlib.contextmanager - def virtualfile_from_xrgrid(self, xrgrid): + def virtualfile_from_xrgrid(self, xrgrid, _grid_mode="GMT_IN"): """ Create a virtual file from an xarray.DataArray object. """ @@ -1906,7 +1909,7 @@ def virtualfile_from_xrgrid(self, xrgrid): matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) - with self.open_virtualfile(family, geometry, "GMT_IN", gmtgrid) as vfile: + with self.open_virtualfile(family, geometry, _grid_mode, gmtgrid) as vfile: yield vfile def virtualfile_to_dataset( diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index 27675ff3744..8b7d53c95b6 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -81,7 +81,9 @@ def grdsample(grid, outgrid: str | None = None, **kwargs): """ with Session() as lib: with ( - lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_in( + check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" + ) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, ): kwargs["G"] = voutgrd From 71094bcab5ce474e190107bca34b7c53c9e0a619 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 16:47:03 +0800 Subject: [PATCH 08/17] Apply the same workaround to grdgradient --- pygmt/src/grdgradient.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index cb947b9b78e..3d2333ee921 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -166,7 +166,9 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs): ) with Session() as lib: with ( - lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_in( + check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" + ) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, ): kwargs["G"] = voutgrd From ebd735902f7c713555a5b36d2e6e5a07c5a7b12a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 16:53:29 +0800 Subject: [PATCH 09/17] Try the same workaround for grdimage --- pygmt/src/grdimage.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdimage.py b/pygmt/src/grdimage.py index a1ba783ab6c..1661130d670 100644 --- a/pygmt/src/grdimage.py +++ b/pygmt/src/grdimage.py @@ -165,7 +165,9 @@ def grdimage(self, grid, **kwargs): with Session() as lib: with ( - lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_in( + check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" + ) as vingrd, lib.virtualfile_in( check_kind="raster", data=kwargs.get("I"), required_data=False ) as vshadegrid, From 2f97f10fe10a0e3e52f56059c7a822e623a8b420 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 16:56:43 +0800 Subject: [PATCH 10/17] Try another workaround --- pygmt/src/grdimage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdimage.py b/pygmt/src/grdimage.py index 1661130d670..6777aa86d9e 100644 --- a/pygmt/src/grdimage.py +++ b/pygmt/src/grdimage.py @@ -166,7 +166,7 @@ def grdimage(self, grid, **kwargs): with Session() as lib: with ( lib.virtualfile_in( - check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" + check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_DUPLICATE" ) as vingrd, lib.virtualfile_in( check_kind="raster", data=kwargs.get("I"), required_data=False From cfefa21e76e8652624f371544b18c67244f7cd5e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 18 Jul 2024 17:05:35 +0800 Subject: [PATCH 11/17] Remove workaround for grdimage --- pygmt/src/grdimage.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pygmt/src/grdimage.py b/pygmt/src/grdimage.py index 6777aa86d9e..a1ba783ab6c 100644 --- a/pygmt/src/grdimage.py +++ b/pygmt/src/grdimage.py @@ -165,9 +165,7 @@ def grdimage(self, grid, **kwargs): with Session() as lib: with ( - lib.virtualfile_in( - check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_DUPLICATE" - ) as vingrd, + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, lib.virtualfile_in( check_kind="raster", data=kwargs.get("I"), required_data=False ) as vshadegrid, From fa5060f7e024565be2f4cc1e5d5c40f1673be03b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 8 Aug 2024 01:27:56 +0800 Subject: [PATCH 12/17] Fix an error --- pygmt/clib/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index c988b869f58..b9b5e0e98e0 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1982,7 +1982,7 @@ def virtualfile_from_xrgrid(self, xrgrid, _grid_mode="GMT_IN"): registration=_reg, pad=self["GMT_PAD_DEFAULT"], ) - if Version(self._info["version"]) < Version("6.5.0"): + if Version(__gmt_version__) < Version("6.5.0"): # Upstream bug fixed in GMT>=6.5.0 self.set_allocmode(family, data) From 4f37629176e0f369a3758e2ab18af3f5228dd94e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Dec 2024 19:08:48 +0800 Subject: [PATCH 13/17] Add __init__ method to Session --- pygmt/clib/session.py | 11 ++++++++--- pygmt/src/grdgradient.py | 6 ++---- pygmt/src/grdsample.py | 6 ++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 0953f10f5d0..b42cca7bc57 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -209,6 +209,12 @@ def info(self) -> dict[str, str]: } return self._info + def __init__(self, mode="GMT_IN"): + """ + Initialize to store session-specific values. + """ + self._mode = mode + def __enter__(self): """ Create a GMT API session. @@ -1808,7 +1814,6 @@ def virtualfile_in( extra_arrays=None, required_z=False, required_data=True, - _grid_mode="GMT_IN", # An internal parameter to workaround GMT API bugs. ): """ Store any data inside a virtual file. @@ -2140,7 +2145,7 @@ def read_virtualfile( return ctp.cast(pointer, ctp.POINTER(dtype)) @contextlib.contextmanager - def virtualfile_from_xrgrid(self, xrgrid, _grid_mode="GMT_IN"): + def virtualfile_from_xrgrid(self, xrgrid): """ Create a virtual file from an xarray.DataArray object. """ @@ -2173,7 +2178,7 @@ def virtualfile_from_xrgrid(self, xrgrid, _grid_mode="GMT_IN"): matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) - with self.open_virtualfile(family, geometry, _grid_mode, gmtgrid) as vfile: + with self.open_virtualfile(family, geometry, self._mode, gmtgrid) as vfile: yield vfile def virtualfile_to_dataset( diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index b0201717bad..3254b9989d1 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -167,11 +167,9 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | No "azimuth, direction, or radiance." ) raise GMTInvalidInput(msg) - with Session() as lib: + with Session(mode="GMT_IN|GMT_IS_REFERENCE") as lib: with ( - lib.virtualfile_in( - check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" - ) as vingrd, + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, ): kwargs["G"] = voutgrd diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index da53e5b1eb7..2de34301f88 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -80,11 +80,9 @@ def grdsample(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | None >>> # and set both x- and y-spacing to 0.5 arc-degrees >>> new_grid = pygmt.grdsample(grid=grid, translate=True, spacing=[0.5, 0.5]) """ - with Session() as lib: + with Session(mode="GMT_IN|GMT_IS_REFERENCE") as lib: with ( - lib.virtualfile_in( - check_kind="raster", data=grid, _grid_mode="GMT_IN|GMT_IS_REFERENCE" - ) as vingrd, + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, ): kwargs["G"] = voutgrd From 8d18a7481f2e452163db0dff874e42dd3a80a214 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Dec 2024 22:11:49 +0800 Subject: [PATCH 14/17] Rename _mode to _in_mode --- pygmt/clib/session.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index b42cca7bc57..abfde28c70c 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -209,11 +209,19 @@ def info(self) -> dict[str, str]: } return self._info - def __init__(self, mode="GMT_IN"): + def __init__(self, in_mode: str = "GMT_IN"): """ - Initialize to store session-specific values. + Initialize to store session-level variables. + + Parameters + ---------- + in_mode + Mode when creating a virtualfile. Defaults to ``"GMT_IN"``. It's used in + :meth:`pygmt.clib.Session.virtualfile_from_xrgrid` only. For some modules + (e.g., ``grdgradient`` and ``grdsample``), we may need + ``"GMT_IN|GMT_IS_REFERENCE"`` due to potential upstream bugs in GMT. """ - self._mode = mode + self._in_mode = in_mode def __enter__(self): """ @@ -2178,7 +2186,7 @@ def virtualfile_from_xrgrid(self, xrgrid): matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) - with self.open_virtualfile(family, geometry, self._mode, gmtgrid) as vfile: + with self.open_virtualfile(family, geometry, self._in_mode, gmtgrid) as vfile: yield vfile def virtualfile_to_dataset( From 9af6b9c54fae6425eb6f1695d018aa86098f8c24 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Dec 2024 22:19:58 +0800 Subject: [PATCH 15/17] Add workaround for grdinfo --- pygmt/clib/session.py | 13 +++++++++++-- pygmt/src/grdinfo.py | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index abfde28c70c..7314c532cd9 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -209,7 +209,7 @@ def info(self) -> dict[str, str]: } return self._info - def __init__(self, in_mode: str = "GMT_IN"): + def __init__(self, in_mode: str = "GMT_IN", grid_as_matrix: bool = False): """ Initialize to store session-level variables. @@ -220,8 +220,12 @@ def __init__(self, in_mode: str = "GMT_IN"): :meth:`pygmt.clib.Session.virtualfile_from_xrgrid` only. For some modules (e.g., ``grdgradient`` and ``grdsample``), we may need ``"GMT_IN|GMT_IS_REFERENCE"`` due to potential upstream bugs in GMT. + grid_as_matrix + Whether to treat the grid as a matrix. Defaults to ``False``. If ``True``, + will use the :meth:`pygmt.clib.Session.virtualfile_from_grid` method instead """ self._in_mode = in_mode + self._grid_as_matrix = grid_as_matrix def __enter__(self): """ @@ -1812,7 +1816,7 @@ def virtualfile_from_stringio( seg.header = None seg.text = None - def virtualfile_in( + def virtualfile_in( # noqa: PLR0912 self, check_kind=None, data=None, @@ -1910,6 +1914,11 @@ def virtualfile_in( "vectors": self.virtualfile_from_vectors, }[kind] + # Patch for upstream bugs where grdinfo -L doesn't work with + # virtualfile_from_xrgrid. + if kind == "grid" and self._grid_as_matrix is True: + _virtualfile_from = self.virtualfile_from_grid + # "_data" is the data that will be passed to the _virtualfile_from function. # "_data" defaults to "data" but should be adjusted for some cases. _data = data diff --git a/pygmt/src/grdinfo.py b/pygmt/src/grdinfo.py index 3194165e528..59d2547251f 100644 --- a/pygmt/src/grdinfo.py +++ b/pygmt/src/grdinfo.py @@ -110,8 +110,11 @@ def grdinfo(grid, **kwargs): info : str A string with information about the grid. """ + # Workaround for upstream bug https://github.com/GenericMappingTools/gmt/issues/8525 + grid_as_matrix = bool(kwargs.get("L")) + with GMTTempFile() as outfile: - with Session() as lib: + with Session(grid_as_matrix=grid_as_matrix) as lib: with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: lib.call_module( module="grdinfo", From 5dbcce98d6d88e036adf377cb74ad2ce6e51d25d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Dec 2024 22:25:37 +0800 Subject: [PATCH 16/17] grdinfo workaround for GMT<=6.5 only --- pygmt/src/grdinfo.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pygmt/src/grdinfo.py b/pygmt/src/grdinfo.py index 59d2547251f..ec021e5acbd 100644 --- a/pygmt/src/grdinfo.py +++ b/pygmt/src/grdinfo.py @@ -2,7 +2,8 @@ grdinfo - Retrieve info about grid file. """ -from pygmt.clib import Session +from packaging.version import Version +from pygmt.clib import Session, __gmt_version__ from pygmt.helpers import ( GMTTempFile, build_arg_list, @@ -111,7 +112,9 @@ def grdinfo(grid, **kwargs): A string with information about the grid. """ # Workaround for upstream bug https://github.com/GenericMappingTools/gmt/issues/8525 - grid_as_matrix = bool(kwargs.get("L")) + grid_as_matrix = Version(__gmt_version__) <= Version("6.5.0") and bool( + kwargs.get("L") + ) with GMTTempFile() as outfile: with Session(grid_as_matrix=grid_as_matrix) as lib: From 744c6d7ac01d730991ec3afabcff03723b84fd22 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 4 Dec 2024 22:59:32 +0800 Subject: [PATCH 17/17] Fix mode to in_mode --- pygmt/src/grdgradient.py | 2 +- pygmt/src/grdsample.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index 3254b9989d1..e3803b486b2 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -167,7 +167,7 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | No "azimuth, direction, or radiance." ) raise GMTInvalidInput(msg) - with Session(mode="GMT_IN|GMT_IS_REFERENCE") as lib: + with Session(in_mode="GMT_IN|GMT_IS_REFERENCE") as lib: with ( lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index 2de34301f88..a4c8777a9cf 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -80,7 +80,7 @@ def grdsample(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | None >>> # and set both x- and y-spacing to 0.5 arc-degrees >>> new_grid = pygmt.grdsample(grid=grid, translate=True, spacing=[0.5, 0.5]) """ - with Session(mode="GMT_IN|GMT_IS_REFERENCE") as lib: + with Session(in_mode="GMT_IN|GMT_IS_REFERENCE") as lib: with ( lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd,