Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e28e846
Pass GMT_GRID virtual file to GMT C API
seisman Apr 17, 2024
b9992ce
Merge branch 'main' into vfile/gmtgrid
seisman Jun 20, 2024
3779b09
Merge branch 'main' into vfile/gmtgrid
seisman Jun 24, 2024
b0b3eec
Test GMT's grdinfo-L branch
seisman Jun 24, 2024
39d39d4
Revert "Test GMT's grdinfo-L branch"
seisman Jun 24, 2024
ce1af4f
Try pad=0
seisman Jun 25, 2024
173ade7
Revert "Try pad=0"
seisman Jun 25, 2024
f7468ba
Merge branch 'main' into vfile/gmtgrid
seisman Jul 10, 2024
e217afa
Merge branch 'main' into vfile/gmtgrid
seisman Jul 17, 2024
b6b6dd8
Merge branch 'main' into vfile/gmtgrid
seisman Jul 18, 2024
5fc4a20
Fix the expected result for grdsample
seisman Jul 18, 2024
c8f31c9
Add an internal parameter to make grdsample work
seisman Jul 18, 2024
71094bc
Apply the same workaround to grdgradient
seisman Jul 18, 2024
ebd7359
Try the same workaround for grdimage
seisman Jul 18, 2024
2f97f10
Try another workaround
seisman Jul 18, 2024
cfefa21
Remove workaround for grdimage
seisman Jul 18, 2024
6a4e877
Merge branch 'main' into vfile/gmtgrid
seisman Jul 24, 2024
f89aed1
Merge branch 'main' into vfile/gmtgrid
seisman Jul 29, 2024
fa5060f
Fix an error
seisman Aug 7, 2024
4245687
Merge branch 'main' into vfile/gmtgrid
seisman Aug 7, 2024
7eb3795
Merge branch 'main' into vfile/gmtgrid
seisman Sep 30, 2024
71a18f9
Merge branch 'main' into vfile/gmtgrid
seisman Dec 4, 2024
4f37629
Add __init__ method to Session
seisman Dec 4, 2024
8d18a74
Rename _mode to _in_mode
seisman Dec 4, 2024
9af6b9c
Add workaround for grdinfo
seisman Dec 4, 2024
5dbcce9
grdinfo workaround for GMT<=6.5 only
seisman Dec 4, 2024
744c6d7
Fix mode to in_mode
seisman Dec 4, 2024
d89a3dc
Merge branch 'main' into vfile/gmtgrid
seisman Feb 19, 2025
428cf02
Merge branch 'main' into vfile/gmtgrid
seisman Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,4 @@ Low level access (these are mostly used by the :mod:`pygmt.clib` package):
clib.Session.virtualfile_from_stringio
clib.Session.virtualfile_from_matrix
clib.Session.virtualfile_from_vectors
clib.Session.virtualfile_from_xrgrid
79 changes: 78 additions & 1 deletion pygmt/clib/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import numpy as np
import pandas as pd
import xarray as xr
from packaging.version import Version
from pygmt.clib.conversion import (
dataarray_to_matrix,
sequence_to_ctypes_array,
Expand All @@ -24,6 +25,7 @@
)
from pygmt.clib.loading import get_gmt_version, load_libgmt
from pygmt.datatypes import _GMT_DATASET, _GMT_GRID, _GMT_IMAGE
from pygmt.datatypes.header import gmt_grdfloat
from pygmt.exceptions import GMTCLibError, GMTCLibNoSessionError, GMTInvalidInput
from pygmt.helpers import (
_validate_data_input,
Expand Down Expand Up @@ -207,6 +209,24 @@
}
return self._info

def __init__(self, in_mode: str = "GMT_IN", grid_as_matrix: bool = False):
"""
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.
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):
"""
Create a GMT API session.
Expand Down Expand Up @@ -327,6 +347,21 @@
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:
msg = f"Failed to set allocation mode of object to external:\n{self._error_message}"
raise GMTCLibError(msg)

Check warning on line 363 in pygmt/clib/session.py

View check run for this annotation

Codecov / codecov/patch

pygmt/clib/session.py#L362-L363

Added lines #L362 - L363 were not covered by tests

def create(self, name: str) -> None:
"""
Create a new GMT C API session.
Expand Down Expand Up @@ -1874,13 +1909,18 @@
"empty": self.virtualfile_from_vectors,
"file": contextlib.nullcontext,
"geojson": tempfile_from_geojson,
"grid": self.virtualfile_from_grid,
"grid": self.virtualfile_from_xrgrid,
"image": tempfile_from_image,
"stringio": self.virtualfile_from_stringio,
"matrix": self.virtualfile_from_matrix,
"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

Check warning on line 1922 in pygmt/clib/session.py

View check run for this annotation

Codecov / codecov/patch

pygmt/clib/session.py#L1922

Added line #L1922 was not covered by tests

# "_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
Expand Down Expand Up @@ -2093,6 +2133,43 @@
dtype = {"dataset": _GMT_DATASET, "grid": _GMT_GRID, "image": _GMT_IMAGE}[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(__gmt_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, self._in_mode, gmtgrid) as vfile:
yield vfile

def virtualfile_to_dataset(
self,
vfname: str,
Expand Down
2 changes: 1 addition & 1 deletion pygmt/src/grdgradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def grdgradient(
"azimuth, direction, or radiance."
)
raise GMTInvalidInput(msg)
with Session() 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,
Expand Down
10 changes: 8 additions & 2 deletions pygmt/src/grdinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"""

import xarray as xr
from packaging.version import Version
from pygmt._typing import PathLike
from pygmt.clib import Session
from pygmt.clib import Session, __gmt_version__
from pygmt.helpers import (
GMTTempFile,
build_arg_list,
Expand Down Expand Up @@ -112,8 +113,13 @@ def grdinfo(grid: PathLike | xr.DataArray, **kwargs) -> str:
info : str
A string with information about the grid.
"""
# Workaround for upstream bug https://github.com/GenericMappingTools/gmt/issues/8525
grid_as_matrix = Version(__gmt_version__) <= Version("6.5.0") and 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",
Expand Down
2 changes: 1 addition & 1 deletion pygmt/src/grdsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def grdsample(
>>> # and set both x- and y-spacings to 0.5 arc-degrees
>>> new_grid = pygmt.grdsample(grid=grid, translate=True, spacing=[0.5, 0.5])
"""
with Session() 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,
Expand Down
10 changes: 5 additions & 5 deletions pygmt/tests/test_grdsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,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],
Expand Down
Loading