def test_Fredholm1(par): """Dot-test and comparison with PyLops for Fredholm1 operator """ _F = \ da.arange(par['nsl'] * par['nx'] * par['ny']).reshape(par['nsl'], par['nx'], par['ny']).rechunk((par['nsl']//2, par['nx'], par['ny'])) F = _F - par['imag'] * _F dFop = dFredholm1(F, nz=par['nz'], saveGt=par['saveGt'], compute=(True, True), dtype=par['dtype']) assert dottest(dFop, par['nsl'] * par['nx'] * par['nz'], par['nsl'] * par['ny'] * par['nz'], chunks=(((par['nsl'] * par['nx'] * par['ny']) // 2), ((par['nsl'] * par['nx'] * par['ny']) // 2)), complexflag=0 if par['imag'] == 0 else 3) x = da.ones((par['nsl'], par['ny'], par['nz']), chunks=(par['nsl'] // 2, par['ny'], par['nz'])) + \ par['imag'] * da.ones((par['nsl'], par['ny'], par['nz']), chunks=(par['nsl'] // 2, par['ny'], par['nz'])) Fop = Fredholm1(F.compute(), nz=par['nz'], saveGt=par['saveGt'], usematmul=True, dtype=par['dtype']) dy = dFop * x.ravel() y = Fop * x.ravel().compute() assert_array_almost_equal(dy, y, decimal=5)
def test_Fredholm1(par): """Dot-test and inversion for Fredholm1 operator""" np.random.seed(10) _F = np.arange(par["nsl"] * par["nx"] * par["ny"]).reshape( par["nsl"], par["nx"], par["ny"] ) F = _F - par["imag"] * _F x = np.ones((par["nsl"], par["ny"], par["nz"])) + par["imag"] * np.ones( (par["nsl"], par["ny"], par["nz"]) ) Fop = Fredholm1( F, nz=par["nz"], saveGt=par["saveGt"], usematmul=par["usematmul"], dtype=par["dtype"], ) assert dottest( Fop, par["nsl"] * par["nx"] * par["nz"], par["nsl"] * par["ny"] * par["nz"], complexflag=0 if par["imag"] == 0 else 3, ) xlsqr = lsqr(Fop, Fop * x.ravel(), damp=1e-20, iter_lim=30, show=0)[0] xlsqr = xlsqr.reshape(par["nsl"], par["ny"], par["nz"]) assert_array_almost_equal(x, xlsqr, decimal=3)
def test_Fredholm1(par): """Dot-test and inversion for Fredholm1 operator """ _F = np.arange(par['nsl'] * par['nx'] * par['ny']).reshape(par['nsl'], par['nx'], par['ny']) F = _F - par['imag'] * _F print(F) x = np.ones((par['nsl'], par['ny'], par['nz'])) + \ par['imag'] * np.ones((par['nsl'], par['ny'], par['nz'])) Fop = Fredholm1(F, nz=par['nz'], saveGt=par['saveGt'], usematmul=par['usematmul'], dtype=par['dtype']) assert dottest(Fop, par['nsl']*par['nx']*par['nz'], par['nsl']*par['ny']*par['nz'], complexflag=0 if par['imag'] == 0 else 3) xlsqr = lsqr(Fop, Fop * x.flatten(), damp=1e-20, iter_lim=30, show=0)[0] xlsqr = xlsqr.reshape(par['nsl'], par['ny'], par['nz']) assert_array_almost_equal(x, xlsqr, decimal=3)
def MDC(G, nt, nv, dt=1., dr=1., twosided=True, fast=None, dtype=None, fftengine='numpy', transpose=True, saveGt=True, conj=False): r"""Multi-dimensional convolution. Apply multi-dimensional convolution between two datasets. If ``transpose=True``, model and data should be provided after flattening 2- or 3-dimensional arrays of size :math:`[n_r (\times n_{vs}) \times n_t]` and :math:`[n_s (\times n_{vs}) \times n_t]` (or :math:`2*n_t-1` for ``twosided=True``), respectively. If ``transpose=False``, model and data should be provided after flattening 2- or 3-dimensional arrays of size :math:`[n_t \times n_r (\times n_{vs})]` and :math:`[n_t \times n_s (\times n_{vs})]` (or :math:`2*n_t-1` for ``twosided=True``), respectively. .. warning:: A new implementation of MDC is provided in v1.5.0. This currently affects only the inner working of the operator and end-users can use the operator in the same way as they used to do with the previous one. Nevertheless, it is now reccomended to use the operator with ``transpose=False``, as this behaviour will become default in version v2.0.0 and the behaviour with ``transpose=True`` will be deprecated. Parameters ---------- G : :obj:`numpy.ndarray` Multi-dimensional convolution kernel in frequency domain of size :math:`[\times n_s \times n_r \times n_{fmax}]` if ``transpose=True`` or size :math:`[n_{fmax} \times n_s \times n_r]` if ``transpose=False`` nt : :obj:`int` Number of samples along time axis nv : :obj:`int` Number of samples along virtual source axis dt : :obj:`float`, optional Sampling of time integration axis dr : :obj:`float`, optional Sampling of receiver integration axis twosided : :obj:`bool`, optional MDC operator has both negative and positive time (``True``) or only positive (``False``) fast : :obj:`bool`, optional *Deprecated*, will be removed in v2.0.0 dtype : :obj:`str`, optional *Deprecated*, will be removed in v2.0.0 fftengine : :obj:`str`, optional Engine used for fft computation (``numpy`` or ``fftw``) transpose : :obj:`bool`, optional Transpose ``G`` and inputs such that time/frequency is placed in first dimension. This allows back-compatibility with v1.4.0 and older but will be removed in v2.0.0 where time/frequency axis will be required to be in first dimension for efficiency reasons. 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 conj : :obj:`str`, optional Perform Fredholm integral computation with complex conjugate of ``G`` See Also -------- MDD : Multi-dimensional deconvolution Notes ----- The so-called multi-dimensional convolution (MDC) is a chained operator [1]_. It is composed of a forward Fourier transform, a multi-dimensional integration, and an inverse Fourier transform: .. math:: y(f, s, v) = \mathscr{F}^{-1} \Big( \int_S G(f, s, r) \mathscr{F}(x(f, r, v)) dr \Big) This operation can be discretized and performed by means of a linear operator .. math:: \mathbf{D}= \mathbf{F}^H \mathbf{G} \mathbf{F} where :math:`\mathbf{F}` is the Fourier transform applied along the time axis and :math:`\mathbf{G}` is the multi-dimensional convolution kernel. .. [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", Geophysical Journal International, vol. 185, pp. 1335-1364. 2011. """ warnings.warn( 'A new implementation of MDC is provided in v1.5.0. This ' 'currently affects only the inner working of the operator, ' 'end-users can continue using the operator in the same way. ' 'Nevertheless, it is now recommended to start using the ' 'operator with transpose=True, as this behaviour will ' 'become default in version v2.0.0 and the behaviour with ' 'transpose=False will be deprecated.', FutureWarning) if twosided and nt % 2 == 0: raise ValueError('nt must be odd number') # transpose G if transpose: G = np.transpose(G, axes=(2, 0, 1)) # create Fredholm operator dtype = G[0, 0, 0].dtype fdtype = (G[0, 0, 0] + 1j * G[0, 0, 0]).dtype Frop = Fredholm1(dr * dt * np.sqrt(nt) * G, nv, saveGt=saveGt, usematmul=False, dtype=fdtype) if conj: Frop = Frop.conj() # create FFT operators nfmax, ns, nr = G.shape # ensure that nfmax is not bigger than allowed nfft = int(np.ceil((nt + 1) / 2)) if nfmax > nfft: nfmax = nfft logging.warning('nfmax set equal to ceil[(nt+1)/2=%d]' % nfmax) Fop = FFT(dims=(nt, nr, nv), dir=0, real=True, fftshift=twosided, engine=fftengine, dtype=fdtype) F1op = FFT(dims=(nt, ns, nv), dir=0, real=True, fftshift=False, engine=fftengine, dtype=fdtype) # create Identity operator to extract only relevant frequencies Iop = Identity(N=nfmax * nr * nv, M=nfft * nr * nv, inplace=True, dtype=dtype) I1op = Identity(N=nfmax * ns * nv, M=nfft * ns * nv, inplace=True, dtype=dtype) F1opH = F1op.H I1opH = I1op.H # create transpose operator if transpose: dims = [nr, nt] if nv == 1 else [nr, nv, nt] axes = (1, 0) if nv == 1 else (2, 0, 1) Top = Transpose(dims, axes, dtype=dtype) dims = [nt, ns] if nv == 1 else [nt, ns, nv] axes = (1, 0) if nv == 1 else (1, 2, 0) TopH = Transpose(dims, axes, dtype=dtype) # create MDC operator MDCop = F1opH * I1opH * Frop * Iop * Fop if transpose: MDCop = TopH * MDCop * Top return MDCop