Source code for magali._utils
# Copyright (c) 2024 The Magali Developers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
#
# This code is part of the Fatiando a Terra project (https://www.fatiando.org)
#
import harmonica as hm
import numpy as np
def _estimate_grid_spacing(data):
"""
Estimate grid spacing as the mean difference in x and y coordinates.
Parameters
----------
data : xr.DataArray
Input data array with coordinates "x" and "y".
Returns
-------
spacing : float
Estimated grid spacing.
"""
return np.mean([np.abs(data.x[1] - data.x[0]), np.abs(data.y[1] - data.y[0])])
[docs]
def gradient(data):
"""
Compute first-order spatial derivatives and total gradient amplitude.
Parameters
----------
data : xr.DataArray
Input data array with coordinates "x" and "y".
Returns
-------
dx : xr.DataArray
First derivative along the x-direction.
dy : xr.DataArray
First derivative along the y-direction.
dz : xr.DataArray
First derivative along the z-direction.
tga : xr.DataArray
Total gradient amplitude.
Notes
-----
The vertical derivative is estimated using the difference between an
upward-continued and a downward-continued version of the data. This avoids
downward continuation, which can amplify noise.
"""
# Compute horizontal derivatives
dx = hm.derivative_easting(data)
dy = hm.derivative_northing(data)
# Estimate grid spacing
spacing = _estimate_grid_spacing(data)
# Compute vertical derivative
data_up = hm.upward_continuation(data, spacing).assign_coords(x=data.x, y=data.y)
data_down = hm.upward_continuation(data, -spacing).assign_coords(x=data.x, y=data.y)
dz = (data_up - data_down) / (2 * spacing)
tga = np.sqrt(dx**2 + dy**2 + dz**2)
return dx, dy, dz, tga
[docs]
def total_gradient_amplitude_grid(data):
"""
Compute the total gradient amplitude (TGA) of a given data array.
The function calculates the horizontal and vertical derivatives of the input data and then
computes the total gradient amplitude.
Parameters
----------
data : xr.DataArray
Input data array with coordinates `x` and `y`.
Returns
-------
tga : xr.DataArray
Dataset containing the total gradient amplitude (TGA).
"""
_, _, _, tga = gradient(data)
# Assign attributes
tga.attrs = {"long_name": "Total Gradient Amplitude", "units": "nT/µm"}
return tga
[docs]
def angular_distance(vectors_a, vectors_b, degrees=True):
"""
Compute the angular distance between pairs of 3D vectors.
The vectors are expressed in Cartesian coordinates (x, y, z) and the
computation uses only NumPy operations.
Parameters
----------
vectors_a : array-like, shape (N, 3)
First array of 3D vectors.
vectors_b : array-like, shape (N, 3)
Second array of 3D vectors.
degrees : bool, optional
If True, return the angular distance in degrees.
Default is True.
Returns
-------
ndarray of shape (N,)
Angular distance between the corresponding vector pairs.
"""
vectors_a = np.atleast_2d(vectors_a)
vectors_b = np.atleast_2d(vectors_b)
dot_products = np.sum(vectors_a * vectors_b, axis=1)
norms_a = np.linalg.norm(vectors_a, axis=1)
norms_b = np.linalg.norm(vectors_b, axis=1)
cos_angles = dot_products / (norms_a * norms_b)
cos_angles = np.clip(cos_angles, -1.0, 1.0)
angles = np.arccos(cos_angles)
return np.degrees(angles) if degrees else angles