Beispiel #1
0
vertlayers = np.cumsum(np.random.uniform(2, 20, 10).astype(np.int))
vertlayers = vertlayers[vertlayers < nx]
nvertlayers = len(vertlayers)

A = 1500 * np.ones((nz, nx))
for top, base in zip(horlayers[:-1], horlayers[1:]):
    A[top:base] = np.random.normal(2000, 200)
for top, base in zip(vertlayers[:-1], vertlayers[1:]):
    A[horlayers[-1]:, top:base] = np.random.normal(2000, 200)

v = np.zeros((2, nz, nx))
v[0, :horlayers[-1]] = 1
v[1, horlayers[-1]:] = 1

Ddop = pylops.FirstDirectionalDerivative((nz, nx), v=v, sampling=(nz, nx))
D2dop = pylops.SecondDirectionalDerivative((nz, nx), v=v, sampling=(nz, nx))

dirder = Ddop * A.ravel()
dirder = dirder.reshape(nz, nx)
dir2der = D2dop * A.ravel()
dir2der = dir2der.reshape(nz, nx)

jump = 4
fig, axs = plt.subplots(3, 1, figsize=(4, 9))
im = axs[0].imshow(A, cmap='gist_rainbow', extent=(0, nx//jump, nz//jump, 0))
q = axs[0].quiver(np.arange(nx//jump)+.5, np.arange(nz//jump)+.5,
                  np.flipud(v[1, ::jump, ::jump]),
                  np.flipud(v[0, ::jump, ::jump]),
                  color='w', linewidths=20)
axs[0].set_title('x')
Beispiel #2
0
def FirstDirectionalDerivative(shape: tuple, directions: np.ndarray, step: Union[float, Tuple[float, ...]] = 1.,
                               edge: bool = True, dtype: str = 'float64',
                               kind: str = 'centered') -> PyLopLinearOperator:
    r"""
    First directional derivative.

    Computes the directional derivative of a multi-dimensional array (at least two dimensions are required)
    along either a single common direction or different ``directions`` for each entry of the array.


    Parameters
    ----------
    shape: tuple
        Shape of the input array.
    directions: np.ndarray
        Single direction (array of size :math:`n_{dims}`) or different directions for each entry (array of size :math:`[n_{dims} \times (n_{d_0} \times ... \times n_{d_{n_{dims}}})]`).
        Each column should be normalised.
    step: Union[float, Tuple[float, ...]]
        Step size in each direction.
    edge: bool
        For ``kind = 'centered'``, use reduced order derivative at edges (``True``) or ignore them (``False``).
    dtype: str
        Type of elements in input vector.
    kind: str
        Derivative kind (``forward``, ``centered``, or ``backward``).

    Returns
    -------
    :py:class:`pycsou.linop.base.PyLopLinearOperator`
        Directional derivative operator.

    Examples
    --------

    .. testsetup::

       import numpy as np
       from pycsou.linop.diff import FirstDirectionalDerivative, FirstDerivative
       from pycsou.util.misc import peaks

    .. doctest::

       >>> x = np.linspace(-2.5, 2.5, 100)
       >>> X,Y = np.meshgrid(x,x)
       >>> Z = peaks(X, Y)
       >>> direction = np.array([1,0])
       >>> Dop = FirstDirectionalDerivative(shape=Z.shape, directions=direction, kind='forward')
       >>> D = FirstDerivative(size=Z.size, shape=Z.shape, kind='forward')
       >>> np.allclose(Dop * Z.flatten(), D * Z.flatten())
       True

    .. plot::

       import numpy as np
       import matplotlib.pyplot as plt
       from pycsou.linop.diff import FirstDirectionalDerivative, FirstDerivative
       from pycsou.util.misc import peaks

       x  = np.linspace(-2.5, 2.5, 25)
       X,Y = np.meshgrid(x,x)
       Z = peaks(X, Y)
       directions = np.zeros(shape=(2,Z.size))
       directions[0, :Z.size//2] = 1
       directions[1, Z.size//2:] = 1
       Dop = FirstDirectionalDerivative(shape=Z.shape, directions=directions)
       y = Dop * Z.flatten()

       plt.figure()
       h = plt.pcolormesh(X,Y,Z, shading='auto')
       plt.quiver(x, x, directions[1].reshape(X.shape), directions[0].reshape(X.shape))
       plt.colorbar(h)
       plt.title('Signal and directions of derivatives')
       plt.figure()
       h = plt.pcolormesh(X,Y,y.reshape(X.shape), shading='auto')
       plt.colorbar(h)
       plt.title('Directional derivatives')
       plt.show()


    Notes
    -----
    The ``FirstDirectionalDerivative`` applies a first-order derivative
    to a multi-dimensional array along the direction defined by the unitary
    vector :math:`\mathbf{v}`:

    .. math::
        d_\mathbf{v}f =
            \langle\nabla f, \mathbf{v}\rangle,

    or along the directions defined by the unitary vectors
    :math:`\mathbf{v}(x, y)`:

    .. math::
        d_\mathbf{v}(x,y) f =
            \langle\nabla f(x,y), \mathbf{v}(x,y)\rangle

    where we have here considered the 2-dimensional case.
    Note that the 2D case, choosing :math:`\mathbf{v}=[1,0]` or :math:`\mathbf{v}=[0,1]`
    is equivalent to the ``FirstDerivative`` operator applied to axis 0 or 1 respectively.

    See Also
    --------
    :py:func:`~pycsou.linop.diff.SecondDirectionalDerivative`, :py:func:`~pycsou.linop.diff.FirstDerivative`

    """
    return PyLopLinearOperator(
        pylops.FirstDirectionalDerivative(dims=shape, v=directions, sampling=step, edge=edge, dtype=dtype, kind=kind))