Skip to content

Commit 73b0edd

Browse files
committed
pygmt.grdvolume: Improve performance by storing output in virtual files
1 parent 2f598c5 commit 73b0edd

File tree

2 files changed

+31
-96
lines changed

2 files changed

+31
-96
lines changed

pygmt/src/grdvolume.py

+25-36
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
grdvolume - Calculate grid volume and area constrained by a contour.
33
"""
44

5+
from typing import Literal
6+
57
import pandas as pd
8+
import xarray as xr
69
from pygmt.clib import Session
710
from pygmt.helpers import (
8-
GMTTempFile,
911
build_arg_string,
1012
fmt_docstring,
1113
kwargs_to_strings,
@@ -24,7 +26,12 @@
2426
V="verbose",
2527
)
2628
@kwargs_to_strings(C="sequence", R="sequence")
27-
def grdvolume(grid, output_type="pandas", outfile=None, **kwargs):
29+
def grdvolume(
30+
grid,
31+
output_type: Literal["pandas", "numpy", "file"] = "pandas",
32+
outfile: str | None = None,
33+
**kwargs,
34+
) -> pd.DataFrame | xr.DataArray | None:
2835
r"""
2936
Determine the volume between the surface of a grid and a plane.
3037
@@ -41,15 +48,8 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs):
4148
Parameters
4249
----------
4350
{grid}
44-
output_type : str
45-
Determine the format the output data will be returned in [Default is
46-
``pandas``]:
47-
48-
- ``numpy`` - :class:`numpy.ndarray`
49-
- ``pandas``- :class:`pandas.DataFrame`
50-
- ``file`` - ASCII file (requires ``outfile``)
51-
outfile : str
52-
The file name for the output ASCII file.
51+
{output_type}
52+
{outfile}
5353
contour : str, float, or list
5454
*cval*\|\ *low/high/delta*\|\ **r**\ *low/high*\|\ **r**\ *cval*.
5555
Find area, volume and mean height (volume/area) inside and above the
@@ -69,14 +69,12 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs):
6969
7070
Returns
7171
-------
72-
ret : pandas.DataFrame or numpy.ndarray or None
72+
ret
7373
Return type depends on ``outfile`` and ``output_type``:
7474
75-
- None if ``outfile`` is set (output will be stored in file set by
76-
``outfile``)
77-
- :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile``
78-
is not set (depends on ``output_type`` [Default is
79-
:class:`pandas.DataFrame`])
75+
- None if ``outfile`` is set (output will be stored in file set by ``outfile``)
76+
- :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` is not set
77+
(depends on ``output_type``)
8078
8179
Example
8280
-------
@@ -103,22 +101,13 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs):
103101
"""
104102
output_type = validate_output_table_type(output_type, outfile=outfile)
105103

106-
with GMTTempFile() as tmpfile:
107-
with Session() as lib:
108-
with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd:
109-
if outfile is None:
110-
outfile = tmpfile.name
111-
lib.call_module(
112-
module="grdvolume",
113-
args=build_arg_string(kwargs, infile=vingrd, outfile=outfile),
114-
)
115-
116-
# Read temporary csv output to a pandas table
117-
if outfile == tmpfile.name: # if user did not set outfile, return pd.DataFrame
118-
result = pd.read_csv(tmpfile.name, sep="\t", header=None, comment=">")
119-
elif outfile != tmpfile.name: # return None if outfile set, output in outfile
120-
result = None
121-
122-
if output_type == "numpy":
123-
result = result.to_numpy()
124-
return result
104+
with Session() as lib:
105+
with (
106+
lib.virtualfile_in(check_kind="raster", data=grid) as vingrd,
107+
lib.virtualfile_out(kind="dataset", fname=outfile) as vouttbl,
108+
):
109+
lib.call_module(
110+
module="grdvolume",
111+
args=build_arg_string(kwargs, infile=vingrd, outfile=vouttbl),
112+
)
113+
return lib.virtualfile_to_dataset(output_type=output_type, vfname=vouttbl)

pygmt/tests/test_grdvolume.py

+6-60
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@
22
Test pygmt.grdvolume.
33
"""
44

5-
from pathlib import Path
6-
75
import numpy as np
86
import numpy.testing as npt
97
import pandas as pd
108
import pytest
119
from pygmt import grdvolume
12-
from pygmt.exceptions import GMTInvalidInput
13-
from pygmt.helpers import GMTTempFile
1410
from pygmt.helpers.testing import load_static_earth_relief
1511

1612

@@ -22,14 +18,6 @@ def fixture_grid():
2218
return load_static_earth_relief()
2319

2420

25-
@pytest.fixture(scope="module", name="region")
26-
def fixture_region():
27-
"""
28-
Set the data region for the tests.
29-
"""
30-
return [-53, -50, -22, -20]
31-
32-
3321
@pytest.fixture(scope="module", name="data")
3422
def fixture_data():
3523
"""
@@ -47,57 +35,15 @@ def fixture_data():
4735
return data
4836

4937

50-
def test_grdvolume_format(grid, region):
51-
"""
52-
Test that correct formats are returned.
53-
"""
54-
grdvolume_default = grdvolume(grid=grid, region=region)
55-
assert isinstance(grdvolume_default, pd.DataFrame)
56-
grdvolume_array = grdvolume(grid=grid, output_type="numpy", region=region)
57-
assert isinstance(grdvolume_array, np.ndarray)
58-
grdvolume_df = grdvolume(grid=grid, output_type="pandas", region=region)
59-
assert isinstance(grdvolume_df, pd.DataFrame)
60-
61-
62-
def test_grdvolume_invalid_format(grid):
63-
"""
64-
Test that grdvolume fails with incorrect output_type argument.
65-
"""
66-
with pytest.raises(GMTInvalidInput):
67-
grdvolume(grid=grid, output_type=1)
68-
69-
70-
def test_grdvolume_no_outfile(grid):
71-
"""
72-
Test that grdvolume fails when output_type set to 'file' but no outfile is
73-
specified.
74-
"""
75-
with pytest.raises(GMTInvalidInput):
76-
grdvolume(grid=grid, output_type="file")
77-
78-
7938
@pytest.mark.benchmark
80-
def test_grdvolume_no_outgrid(grid, data, region):
39+
def test_grdvolume(grid, data):
8140
"""
82-
Test the expected output of grdvolume with no output file set.
41+
Test the basic functionality of grdvolume.
8342
"""
8443
test_output = grdvolume(
85-
grid=grid, contour=[200, 400, 50], output_type="numpy", region=region
44+
grid=grid,
45+
contour=[200, 400, 50],
46+
region=[-53, -50, -22, -20],
8647
)
48+
assert isinstance(test_output, pd.DataFrame)
8749
npt.assert_allclose(test_output, data)
88-
89-
90-
def test_grdvolume_outgrid(grid, region):
91-
"""
92-
Test the expected output of grdvolume with an output file set.
93-
"""
94-
with GMTTempFile(suffix=".csv") as tmpfile:
95-
result = grdvolume(
96-
grid=grid,
97-
contour=[200, 400, 50],
98-
output_type="file",
99-
outfile=tmpfile.name,
100-
region=region,
101-
)
102-
assert result is None # return value is None
103-
assert Path(tmpfile.name).stat().st_size > 0 # check that outfile exists

0 commit comments

Comments
 (0)