8000 Merge pull request #5186 from pseudocubic/gradient-boundary-order-key… · numpy/numpy@4c0747d · GitHub
[go: up one dir, main page]

Skip to content

Commit 4c0747d

Browse files
committed
Merge pull request #5186 from pseudocubic/gradient-boundary-order-keyword
BUG: Fixes #5184 gradient calculation behavior at boundaries
2 parents 51f0976 + 8969da5 commit 4c0747d

File tree

2 files changed

+33
-22
lines changed

2 files changed

+33
-22
lines changed

numpy/lib/function_base.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -883,28 +883,33 @@ def copy(a, order='K'):
883883
# Basic operations
884884

885885

886-
def gradient(f, *varargs):
886+
def gradient(f, *varargs, **kwargs):
887887
"""
888888
Return the gradient of an N-dimensional array.
889-
889+
890890
The gradient is computed using second order accurate central differences
891-
in the interior and second order accurate one-sides (forward or backwards)
892-
differences at the boundaries. The returned gradient hence has the same
893-
shape as the input array.
891+
in the interior and either first differences or second order accurate
892+
one-sides (forward or backwards) differences at the boundaries. The
893+
returned gradient hence has the same shape as the input array.
894894
895895
Parameters
896896
----------
897897
f : array_like
898-
An N-dimensional array containing samples of a scalar function.
899-
`*varargs` : scalars
900-
0, 1, or N scalars specifying the sample distances in each direction,
901-
that is: `dx`, `dy`, `dz`, ... The default distance is 1.
898+
An N-dimensional array containing samples of a scalar function.
899+
varargs : list of scalar, optional
900+
N scalars specifying the sample distances for each dimension,
901+
i.e. `dx`, `dy`, `dz`, ... Default distance: 1.
902+
edge_order : {1, 2}, optional
903+
Gradient is calculated using N\ :sup:`th` order accurate differences
904+
at the boundaries. Default: 1.
905+
906+
.. versionadded:: 1.9.1
902907
903908
Returns
904909
-------
905910
gradient : ndarray
906-
N arrays of the same shape as `f` giving the derivative of `f` with
907-
respect to each dimension.
911+
N arrays of the same shape as `f` giving the derivative of `f` with
912+
respect to each dimension.
908913
909914
Examples
910915
--------
@@ -916,15 +921,14 @@ def gradient(f, *varargs):
916921
917922
>>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=np.float))
918923
[array([[ 2., 2., -1.],
919-
[ 2., 2., -1.]]),
920-
array([[ 1. , 2.5, 4. ],
921-
[ 1. , 1. , 1. ]])]
924+
[ 2., 2., -1.]]), array([[ 1. , 2.5, 4. ],
925+
[ 1. , 1. , 1. ]])]
922926
923-
>>> x = np.array([0,1,2,3,4])
924-
>>> dx = gradient(x)
927+
>>> x = np.array([0, 1, 2, 3, 4])
928+
>>> dx = np.gradient(x)
925929
>>> y = x**2
926-
>>> gradient(y,dx)
927-
array([0., 2., 4., 6., 8.])
930+
>>> np.gradient(y, dx, edge_order=2)
931+
array([-0., 2., 4., 6., 8.])
928932
"""
929933
f = np.asanyarray(f)
930934
N = len(f.shape) # number of dimensions
@@ -939,6 +943,13 @@ def gradient(f, *varargs):
939943
raise SyntaxError(
940944
"invalid number of arguments")
941945

946+
edge_order = kwargs.pop('edge_order', 1)
947+
if kwargs:
948+
raise TypeError('"{}" are not valid keyword arguments.'.format(
949+
'", "'.join(kwargs.keys())))
950+
if edge_order > 2:
951+
raise ValueError("'edge_order' greater than 2 not supported")
952+
942953
# use central differences on interior and one-sided differences on the
943954
# endpoints. This preserves second order-accuracy over the full domain.
944955

@@ -978,7 +989,7 @@ def gradient(f, *varargs):
978989
"at least two elements are required.")
979990

980991
# Numerical differentiation: 1st order edges, 2nd order interior
981-
if y.shape[axis] == 2:
992+
if y.shape[axis] == 2 or edge_order == 1:
982993
# Use first order differences for time data
983994
out = np.empty_like(y, dtype=otype)
984995

numpy/lib/tests/test_function_base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def test_datetime64(self):
536536
'1910-10-12', '1910-12-12', '1912-12-12'],
537537
dtype='datetime64[D]')
538538
dx = np.array(
539-
[-7, -3, 0, 31, 61, 396, 1066],
539+
[-5, -3, 0, 31, 61, 396, 731],
540540
dtype='timedelta64[D]')
541541
assert_array_equal(gradient(x), dx)
542542
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -547,7 +547,7 @@ def test_timedelta64(self):
547547
[-5, -3, 10, 12, 61, 321, 300],
548548
dtype='timedelta64[D]')
549549
dx = np.array(
550-
[-3, 7, 7, 25, 154, 119, -161],
550+
[2, 7, 7, 25, 154, 119, -21],
551551
dtype='timedelta64[D]')
552552
assert_array_equal(gradient(x), dx)
553553
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -561,7 +561,7 @@ def test_second_order_accurate(self):
561561
dx = x[1] - x[0]
562562
y = 2 * x ** 3 + 4 * x ** 2 + 2 * x
563563
analytical = 6 * x ** 2 + 8 * x + 2
564-
num_error = np.abs((np.gradient(y, dx) / analytical) - 1)
564+
num_error = np.abs((np.gradient(y, dx, edge_order=2) / analytical) - 1)
565565
assert_(np.all(num_error < 0.03) == True)
566566

567567

0 commit comments

Comments
 (0)
0