예제 #1
0
파일: mdd.py 프로젝트: ETDelaney/pylops
def MDD(G,
        d,
        dt=0.004,
        dr=1.,
        nfmax=None,
        wav=None,
        twosided=True,
        causality_precond=False,
        adjoint=False,
        psf=False,
        dtype='float64',
        dottest=False,
        saveGt=True,
        add_negative=True,
        **kwargs_lsqr):
    r"""Multi-dimensional deconvolution.

    Solve multi-dimensional deconvolution problem using
    :py:func:`scipy.sparse.linalg.lsqr` iterative solver.

    Parameters
    ----------
    G : :obj:`numpy.ndarray`
        Multi-dimensional convolution kernel in time domain of size
        :math:`[n_s \times n_r \times n_t]` for ``twosided=False`` or
        ``twosided=True`` and ``add_negative=True``
        (with only positive times) or size
        :math:`[n_s \times n_r \times 2*n_t-1]` for ``twosided=True`` and
        ``add_negative=False``
        (with both positive and negative times)
    d : :obj:`numpy.ndarray`
        Data in time domain :math:`[n_s (\times n_vs) \times n_t]`
    dt : :obj:`float`, optional
        Sampling of time integration axis
    dr : :obj:`float`, optional
        Sampling of receiver integration axis
    nfmax : :obj:`int`, optional
        Index of max frequency to include in deconvolution process
    wav : :obj:`numpy.ndarray`, optional
        Wavelet to convolve to the inverted model and psf. If ``None``, the
        outputs of the inversion are returned directly
    twosided : :obj:`bool`, optional
        MDC operator and data both negative and positive time (``True``)
        or only positive (``False``)
    add_negative : :obj:`bool`, optional
        Add negative side to MDC operator and data (``True``) or not
        (``False``)- operator and data are already provided with both positive
        and negative sides. To be used only with ``twosided=True``.
    causality_precond : :obj:`bool`, optional
        Apply causality mask (``True``) or not (``False``)
    adjoint : :obj:`bool`, optional
        Compute and return adjoint(s)
    psf : :obj:`bool`, optional
        Compute and return Point Spread Function (PSF) and its inverse
    dtype : :obj:`bool`, optional
        Type of elements in input array.
    dottest : :obj:`bool`, optional
        Apply dot-test
    saveGt : :obj:`bool`, optional
        Save ``G`` and ``G^H`` to speed up the computation of adjoint of
        :class:`pylops.signalprocessing.Fredholm1` (``True``) or create
        ``G^H`` on-the-fly (``False``) Note that ``saveGt=True`` will be
        faster but double the amount of required memory
    **kwargs_lsqr
        Arbitrary keyword arguments for
        :py:func:`scipy.sparse.linalg.lsqr` solver

    Returns
    -------
    minv : :obj:`numpy.ndarray`
        Inverted model of size :math:`[n_r (\times n_{vs}) \times n_t]`
        for ``twosided=False`` or
        :math:`[n_r (\times n_vs) \times 2*n_t-1]` for ``twosided=True``
    madj : :obj:`numpy.ndarray`
        Adjoint model of size :math:`[n_r (\times n_{vs}) \times n_t]`
        for ``twosided=False`` or
        :math:`[n_r (\times n_r) \times 2*n_t-1]` for ``twosided=True``
    psfinv : :obj:`numpy.ndarray`
        Inverted psf of size :math:`[n_r \times n_r \times n_t]`
        for ``twosided=False`` or
        :math:`[n_r \times n_r \times 2*n_t-1]` for ``twosided=True``
    psfadj : :obj:`numpy.ndarray`
        Adjoint psf of size :math:`[n_r \times n_r \times n_t]`
        for ``twosided=False`` or
        :math:`[n_r \times n_r \times 2*n_t-1]` for ``twosided=True``

    See Also
    --------
    MDC : Multi-dimensional convolution

    Notes
    -----
    Multi-dimensional deconvolution (MDD) is a mathematical ill-solved problem,
    well-known in the image processing and geophysical community [1]_.

    MDD aims at removing the effects of a Multi-dimensional Convolution
    (MDC) kernel or the so-called blurring operator or point-spread
    function (PSF) from a given data. It can be written as

    .. math::
        \mathbf{d}= \mathbf{D} \mathbf{m}

    or, equivalently, by means of its normal equation

    .. math::
        \mathbf{m}= (\mathbf{D}^H\mathbf{D})^{-1} \mathbf{D}^H\mathbf{d}

    where :math:`\mathbf{D}^H\mathbf{D}` is the PSF.

    .. [1] Wapenaar, K., van der Neut, J., Ruigrok, E., Draganov, D., Hunziker,
       J., Slob, E., Thorbecke, J., and Snieder, R., "Seismic interferometry
       by crosscorrelation and by multi-dimensional deconvolution: a
       systematic comparison", Geophyscial Journal International, vol. 185,
       pp. 1335-1364. 2011.

    """
    ns, nr, nt = G.shape
    if len(d.shape) == 2:
        ns, nt = d.shape
        nv = 1
    else:
        ns, nv, nt = d.shape
    if twosided:
        if add_negative:
            nt2 = 2 * nt - 1
        else:
            nt2 = nt
            nt = (nt2 + 1) // 2
        nfmax_allowed = int(np.ceil((nt2 + 1) / 2))
    else:
        nt2 = nt
        nfmax_allowed = nt

    # Fix nfmax to be at maximum equal to half of the size of fft samples
    if nfmax is None or nfmax > nfmax_allowed:
        nfmax = nfmax_allowed
        logging.warning('nfmax set equal to ceil[(nt+1)/2=%d]' % nfmax)

    # Add negative part to data and model
    if twosided and add_negative:
        G = np.concatenate((np.zeros((ns, nr, nt - 1)), G), axis=-1)
        d = np.concatenate((np.squeeze(np.zeros((ns, nv, nt - 1))), d),
                           axis=-1)

    # Bring kernel to frequency domain
    Gfft = np.fft.rfft(G, nt2, axis=-1)
    Gfft = Gfft[..., :nfmax]

    # Bring frequency/time to first dimension
    Gfft = np.moveaxis(Gfft, -1, 0)
    d = np.moveaxis(d, -1, 0)
    if psf:
        G = np.moveaxis(G, -1, 0)

    # Define MDC linear operator
    MDCop = MDC(Gfft,
                nt2,
                nv=nv,
                dt=dt,
                dr=dr,
                twosided=twosided,
                transpose=False,
                saveGt=saveGt)
    if psf:
        PSFop = MDC(Gfft,
                    nt2,
                    nv=nr,
                    dt=dt,
                    dr=dr,
                    twosided=twosided,
                    transpose=False,
                    saveGt=saveGt)
    if dottest:
        Dottest(MDCop, nt2 * ns * nv, nt2 * nr * nv, verb=True)
        if psf:
            Dottest(PSFop, nt2 * ns * nr, nt2 * nr * nr, verb=True)

    # Adjoint
    if adjoint:
        madj = MDCop.H * d.flatten()
        madj = np.squeeze(madj.reshape(nt2, nr, nv))
        madj = np.moveaxis(madj, 0, -1)
        if psf:
            psfadj = PSFop.H * G.flatten()
            psfadj = np.squeeze(psfadj.reshape(nt2, nr, nr))
            psfadj = np.moveaxis(psfadj, 0, -1)

    # Inverse
    if twosided and causality_precond:
        P = np.ones((nt2, nr, nv))
        P[:nt - 1] = 0
        Pop = Diagonal(P)
        minv = PreconditionedInversion(MDCop,
                                       Pop,
                                       d.flatten(),
                                       returninfo=False,
                                       **kwargs_lsqr)
    else:
        minv = lsqr(MDCop, d.flatten(), **kwargs_lsqr)[0]
    minv = np.squeeze(minv.reshape(nt2, nr, nv))
    minv = np.moveaxis(minv, 0, -1)
    if wav is not None:
        minv = sp_convolve1d(minv, wav, axis=-1)

    if psf:
        psfinv = lsqr(PSFop, G.flatten(), **kwargs_lsqr)[0]
        psfinv = np.squeeze(psfinv.reshape(nt2, nr, nr))
        psfinv = np.moveaxis(psfinv, 0, -1)
        if wav is not None:
            psfinv = sp_convolve1d(psfinv, wav, axis=-1)

    if adjoint and psf:
        return minv, madj, psfinv, psfadj
    elif adjoint:
        return minv, madj
    elif psf:
        return minv, psfinv
    else:
        return minv
예제 #2
0
def MDD(G, d, dt=0.004, dr=1., nfmax=None, wav=None,
        twosided=True, causality_precond=False, adjoint=False,
        psf=False, dtype='complex64',
        dottest=False, **kwargs_lsqr):
    r"""Multi-dimensional deconvolution.

    Solve multi-dimensional deconvolution problem using :py:func:`scipy.sparse.linalg.lsqr`
    iterative solver.

    Parameters
    ----------
    G : :obj:`numpy.ndarray`
        Multi-dimensional convolution kernel  in frequency domain of size
        :math:`[n_s \times n_r \times n_{fmax}]`
    d : :obj:`numpy.ndarray`
        Data in time domain :math:`[ns (\times nr) \times nt]`
    dt : :obj:`float`, optional
        Sampling of time integration axis
    dr : :obj:`float`, optional
        Sampling of receiver integration axis
    nfmax : :obj:`int`, optional
        Index of max frequency to include in deconvolution process
    twosided : :obj:`bool`, optional
        MDC operator has both negative and positive time (``True``)
        or only positive (``False``)
    causality_precond : :obj:`bool`, optional
        Type of elements in input array.
    adjoint : :obj:`bool`, optional
        Compute and return adjoint(s)
    psf : :obj:`bool`, optional
        Compute and return Point Spread Function (PSF) and its inverse
    dtype : :obj:`bool`, optional
        Type of elements in input array.
    dottest : :obj:`bool`, optional
        Apply dot-test
    **kwargs_lsqr
        Arbitrary keyword arguments for :py:func:`scipy.sparse.linalg.lsqr` solver

    Returns
    ----------
    minv: :obj:`numpy.ndarray`
        Inverted model.
    madj: :obj:`numpy.ndarray`
        Adjoint model.
    psfinv: :obj:`numpy.ndarray`
        Inverted psf.
    psfadj: :obj:`numpy.ndarray`
        Adjoint psf.

    See Also
    --------
    MDC : Multi-dimensional convolution

    Notes
    -----
    Multi-dimensional deconvolution (MDD) is a mathematical ill-solved problem,
    well-known in the image processing and geophysical community [1]_.

    MDD aims at removing the effects of a Multi-dimensional Convolution (MDC) kernel
    or the so-called blurring operator or point-spread function (PSF) from a given data.
    It can be written as

    .. math::
        \mathbf{d}= \mathbf{D} \mathbf{m}

    or, equivalently, by means of its normal equation

    .. math::
        \mathbf{m}= (\mathbf{D}^H\mathbf{D})^{-1} \mathbf{D}^H\mathbf{d}$$

    where :math:`\mathbf{D}^H\mathbf{D}` is the PSF.

    .. [1] Wapenaar, K., van der Neut, J., Ruigrok, E., Draganov, D., Hunziker, J.,
       Slob, E., Thorbecke, J., and Snieder, R., "Seismic interferometry by crosscorrelation
       and by multi-dimensional deconvolution: a systematic comparison",
       Geophyscial Journal International, vol. 185, pp. 1335-1364. 2011.

    """
    ns, nr, nt = G.shape
    if len(d.shape) == 2:
        ns, nt = d.shape
        nv = 1
    else:
        ns, nv, nt = d.shape
    nt2 = nt if twosided == False else 2 * nt - 1

    # Fix nfmax to be at maximum equal to half of the size of fft samples
    if nfmax == None or nfmax > np.ceil((nt2 + 1) / 2):
        nfmax = int(np.ceil((nt2+1)/2))
        logging.warning('nfmax set equal to (nt+1)/2=%d' % nfmax)

    # Add negative part to data and model
    if twosided:
        G = np.concatenate((np.zeros((ns, nr, nt - 1)), G), axis=-1)
        d = np.concatenate((np.squeeze(np.zeros((ns, nv, nt - 1))), d), axis=-1)

    # Define MDC linear operator
    Gfft = np.fft.rfft(G, nt2, axis=-1)
    Gfft = Gfft[..., :nfmax]

    MDCop = MDC(Gfft, nt2, nv=nv, dt=dt, dr=dr, twosided=twosided, dtype=dtype)
    if psf:
        PSFop = MDC(Gfft, nt2, nv=nr, dt=dt, dr=dr, twosided=twosided, dtype=dtype)
    if dottest:
        Dottest(MDCop, nt2*ns*nv, nt2*nr*nv, verb=True)
        if psf:
            Dottest(PSFop, nt2 * ns * nr, nt2 * nr * nr, verb=True)

    # Adjoint
    if adjoint:
        madj = MDCop.H * d.flatten()
        madj = np.squeeze(madj.reshape(nr, nv, nt2))
        if psf:
            psfadj = PSFop.H * G.flatten()
            psfadj = np.squeeze(psfadj.reshape(nr, nr, nt2))

    # Inverse
    if twosided and causality_precond:
        P = np.ones((nr, nv, nt2))
        P[:, :, :nt - 1] = 0
        Pop = Diagonal(P)
        minv = PreconditionedInversion(MDCop, Pop, d.flatten(), returninfo=False, **kwargs_lsqr)
    else:
        minv = lsqr(MDCop, d.flatten(), **kwargs_lsqr)[0]
    minv = np.squeeze(minv.reshape(nr, nv, nt2))
    if wav is not None:
        minv = sp_convolve1d(minv, wav, axis=-1)

    if psf:
        psfinv = lsqr(PSFop, G.flatten(), **kwargs_lsqr)[0]
        psfinv = np.squeeze(psfinv.reshape(nr, nr, nt2))
        if wav is not None:
            psfinv = sp_convolve1d(psfinv, wav, axis=-1)

    if adjoint and psf:
        return minv, madj, psfinv, psfadj
    elif adjoint:
        return minv, madj
    elif psf:
        return minv, psfinv
    else:
        return minv