Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 52 additions & 0 deletions harmonica/_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,58 @@ def reduction_to_pole(
)


def total_horizontal_gradient(grid):
r"""
Calculate the total horizontal derivative of a potential field grid.

Compute the amplitude of the horizontal gradient of a regular gridded
potential field `M`. This is a measure of the rate of change in the x and y
(horizontal) directions. . The horizontal derivatives are calculated though
finite-differences.

Parameters
----------
grid : :class:`xarray.DataArray`
A two-dimensional :class:`xarray.DataArray` whose coordinates are
evenly spaced (regular grid). Its dimensions should be in the following
order: *northing*, *easting*. The coordinates must be defined in the same units.

Returns
-------
horizontal_derivative_grid : :class:`xarray.DataArray`
A :class:`xarray.DataArray` containing the total horizontal derivative of
the input ``grid``.

Notes
-----
The total horizontal derivative is calculated as:

.. math::

A(x, y) = \sqrt{
\left( \frac{\partial M}{\partial x} \right)^2
+ \left( \frac{\partial M}{\partial y} \right)^2
}

where :math:`M` is the regularly gridded potential field.

References
----------
[Blakely1995]_
[CordellGrauch1985]_
"""

# Run sanity checks on the grid
grid_sanity_checks(grid)
# Calculate the horizontal gradients of the grid
horizontal_gradient = (
derivative_easting(grid, order=1),
derivative_northing(grid, order=1)
)
# return the total horizontal gradient
return np.sqrt(horizontal_gradient[0] ** 2 + horizontal_gradient[1] ** 2)


def total_gradient_amplitude(grid):
r"""
Calculates the total gradient amplitude of a potential field grid
Expand Down
65 changes: 65 additions & 0 deletions harmonica/tests/test_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
reduction_to_pole,
tilt_angle,
total_gradient_amplitude,
total_horizontal_gradient,
upward_continuation,
)
from .utils import root_mean_square_error
Expand Down Expand Up @@ -602,6 +603,70 @@ def test_invalid_grid_with_nans(self, sample_potential):
total_gradient_amplitude(sample_potential)


class TestTotalHorizontalGradient:
"""
Test total_horizontal_gradient function
"""

def test_against_synthetic(
self, sample_potential, sample_g_n, sample_g_e
):
"""
Test total_horizontal_gradient function against the synthetic model
"""
pad_width = {
"easting": sample_potential.easting.size // 3,
"northing": sample_potential.northing.size // 3,
}
potential_padded = xrft.pad(
sample_potential.drop_vars("upward"),
pad_width=pad_width,
)
thg = total_horizontal_gradient(potential_padded)
thg = xrft.unpad(thg, pad_width)

trim = 6
thg = thg[trim:-trim, trim:-trim]
g_e = sample_g_e[trim:-trim, trim:-trim] * 1e-5 # convert to SI
g_n = sample_g_n[trim:-trim, trim:-trim] * 1e-5
g_thg = np.sqrt(g_e**2 + g_n**2)
rms = root_mean_square_error(thg, g_thg)
assert rms / np.abs(g_thg).max() < 0.1

def test_invalid_grid_single_dimension(self):
"""
Check if total_horizontal_gradient raises error on grid with single
dimension
"""
x = np.linspace(0, 10, 11)
y = x**2
grid = xr.DataArray(y, coords={"x": x}, dims=("x",))
with pytest.raises(ValueError, match="Invalid grid with 1 dimensions."):
total_horizontal_gradient(grid)

def test_invalid_grid_three_dimensions(self):
"""
Check if total_horizontal_gradient raises error on grid with three
dimensions
"""
x = np.linspace(0, 10, 11)
y = np.linspace(-4, 4, 9)
z = np.linspace(20, 30, 5)
xx, yy, zz = np.meshgrid(x, y, z)
data = xx + yy + zz
grid = xr.DataArray(data, coords={"x": x, "y": y, "z": z}, dims=("y", "x", "z"))
with pytest.raises(ValueError, match="Invalid grid with 3 dimensions."):
total_horizontal_gradient(grid)

def test_invalid_grid_with_nans(self, sample_potential):
"""
Check if total_horizontal_gradient raises error if grid contains nans
"""
sample_potential.values[0, 0] = np.nan
with pytest.raises(ValueError, match="Found nan"):
total_horizontal_gradient(sample_potential)


class TestTilt:
"""
Test tilt function
Expand Down
Loading