示例#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')
axs[0].axis('tight')
示例#2
0
def SecondDirectionalDerivative(shape: tuple, directions: np.ndarray, step: Union[float, Tuple[float, ...]] = 1.,
                                edge: bool = True, dtype: str = 'float64'):
    r"""
    Second directional derivative.

    Computes the second 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
        Use reduced order derivative at edges (``True``) or ignore them (``False``).
    dtype: str
        Type of elements in input vector.

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

    Examples
    --------

    .. testsetup::

       import numpy as np
       from pycsou.linop.diff import SecondDirectionalDerivative
       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 = SecondDirectionalDerivative(shape=Z.shape, directions=direction)
       >>> dir_d2 = (Dop * Z.reshape(-1)).reshape(Z.shape)

    .. plot::

       import numpy as np
       import matplotlib.pyplot as plt
       from pycsou.linop.diff import FirstDirectionalDerivative, SecondDirectionalDerivative
       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)
       Dop2 = SecondDirectionalDerivative(shape=Z.shape, directions=directions)
       y = Dop * Z.flatten()
       y2 = Dop2 * 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.quiver(x, x, directions[1].reshape(X.shape), directions[0].reshape(X.shape))
       plt.colorbar(h)
       plt.title('First Directional derivatives')
       plt.figure()
       h = plt.pcolormesh(X,Y,y2.reshape(X.shape), shading='auto')
       plt.colorbar(h)
       plt.title('Second Directional derivatives')
       plt.show()



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

    .. math::
        d^2_\mathbf{v} f =
            - d_\mathbf{v}^\ast (d_\mathbf{v} f)

    where :math:`d_\mathbf{v}` is the first-order directional derivative
    implemented by :py:func:`~pycsou.linop.diff.FirstDirectionalDerivative`. The above formula generalises the well-known relationship:

    .. math::
        \Delta f= -\text{div}(\nabla f),

    where minus the divergence operator is the adjoint of the gradient.

    **Note that problematic values at edges are set to zero.**

    See Also
    --------
    :py:func:`~pycsou.linop.diff.FirstDirectionalDerivative`, :py:func:`~pycsou.linop.diff.SecondDerivative`

    """
    Pylop = PyLopLinearOperator(
        pylops.SecondDirectionalDerivative(dims=shape, v=directions, sampling=step, edge=edge, dtype=dtype))
    kill_edges = np.ones(shape=shape)
    for axis in range(len(shape)):
        kill_edges = np.swapaxes(kill_edges, axis, 0)
        kill_edges[-2:] = 0
        kill_edges[:2] = 0
        kill_edges = np.swapaxes(kill_edges, 0, axis)
    KillEdgeOp = DiagonalOperator(kill_edges.reshape(-1))
    DirD2 = KillEdgeOp * Pylop
    return DirD2