|
1 | 1 | import logging |
| 2 | +import numpy as np |
| 3 | +import dask.array as da |
2 | 4 | from pylops.waveeqprocessing.mdd import _MDC |
3 | 5 |
|
| 6 | +from pylops_distributed.utils import dottest as Dottest |
4 | 7 | from pylops_distributed import Identity, Transpose |
5 | 8 | from pylops_distributed.signalprocessing import FFT, Fredholm1 |
| 9 | +from pylops_distributed.optimization.cg import cgls |
6 | 10 |
|
7 | 11 | logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) |
8 | 12 |
|
9 | 13 |
|
10 | 14 | def MDC(G, nt, nv, dt=1., dr=1., twosided=True, |
11 | | - saveGt=True, conj=False, prescaled=False, |
| 15 | + saveGt=False, conj=False, prescaled=False, |
12 | 16 | compute=(False, False), todask=(False, False)): |
13 | 17 | r"""Multi-dimensional convolution. |
14 | 18 |
|
@@ -73,3 +77,126 @@ def MDC(G, nt, nv, dt=1., dr=1., twosided=True, |
73 | 77 | (nt, G.shape[1], nv)), |
74 | 78 | 'todask': (todask[1], False), |
75 | 79 | 'compute':(False, compute[0])}) |
| 80 | + |
| 81 | + |
| 82 | + |
| 83 | +def MDD(G, d, dt=0.004, dr=1., nfmax=None, wav=None, |
| 84 | + twosided=True, adjoint=False, dottest=False, |
| 85 | + saveGt=False, add_negative=True, **kwargs_cgls): |
| 86 | + r"""Multi-dimensional deconvolution. |
| 87 | +
|
| 88 | + Solve multi-dimensional deconvolution problem using |
| 89 | + :py:func:`scipy.sparse.linalg.lsqr` iterative solver. |
| 90 | +
|
| 91 | + Parameters |
| 92 | + ---------- |
| 93 | + G : :obj:`dask.array.ndarray` |
| 94 | + Multi-dimensional convolution kernel in frequency domain of size |
| 95 | + :math:`[n_{f,max} \times n_s \times n_r]` |
| 96 | + d : :obj:`dask.array.ndarray` |
| 97 | + Data in time domain :math:`[n_t \times n_s (\times n_vs)]` if |
| 98 | + ``twosided=False`` or ``twosided=True`` and ``add_negative=True`` |
| 99 | + (with only positive times) or size |
| 100 | + :math:`[2*n_t-1 \times n_s (\times n_vs)]` if ``twosided=True`` |
| 101 | + dt : :obj:`float`, optional |
| 102 | + Sampling of time integration axis |
| 103 | + dr : :obj:`float`, optional |
| 104 | + Sampling of receiver integration axis |
| 105 | + nfmax : :obj:`int`, optional |
| 106 | + Index of max frequency to include in deconvolution process |
| 107 | + wav : :obj:`numpy.ndarray`, optional |
| 108 | + Wavelet to convolve to the inverted model and psf |
| 109 | + (must be centered around its index in the middle of the array). |
| 110 | + If ``None``, the outputs of the inversion are returned directly. |
| 111 | + twosided : :obj:`bool`, optional |
| 112 | + MDC operator and data both negative and positive time (``True``) |
| 113 | + or only positive (``False``) |
| 114 | + add_negative : :obj:`bool`, optional |
| 115 | + Add negative side to MDC operator and data (``True``) or not |
| 116 | + (``False``)- operator and data are already provided with both positive |
| 117 | + and negative sides. To be used only with ``twosided=True``. |
| 118 | + adjoint : :obj:`bool`, optional |
| 119 | + Compute and return adjoint(s) |
| 120 | + dottest : :obj:`bool`, optional |
| 121 | + Apply dot-test |
| 122 | + saveGt : :obj:`bool`, optional |
| 123 | + Save ``G`` and ``G^H`` to speed up the computation of adjoint of |
| 124 | + :class:`pylops_distributed.signalprocessing.Fredholm1` (``True``) or |
| 125 | + create ``G^H`` on-the-fly (``False``) Note that ``saveGt=True`` will be |
| 126 | + faster but double the amount of required memory |
| 127 | + **kwargs_cgls |
| 128 | + Arbitrary keyword arguments for |
| 129 | + :py:func:`pylops_distributed.optimization.cg.cgls` solver |
| 130 | +
|
| 131 | + Returns |
| 132 | + ------- |
| 133 | + minv : :obj:`dask.array.ndarray` |
| 134 | + Inverted model of size :math:`[n_t \times n_r (\times n_{vs})]` |
| 135 | + for ``twosided=False`` or |
| 136 | + :math:`[2*n_t-1 \times n_r (\times n_vs)]` for ``twosided=True`` |
| 137 | + madj : :obj:`dask.array.ndarray` |
| 138 | + Adjoint model of size :math:`[n_t \times n_r (\times n_{vs})]` |
| 139 | + for ``twosided=False`` or |
| 140 | + :math:`[2*n_t-1 \times n_r (\times n_r) ]` for ``twosided=True`` |
| 141 | +
|
| 142 | + See Also |
| 143 | + -------- |
| 144 | + MDC : Multi-dimensional convolution |
| 145 | +
|
| 146 | + Notes |
| 147 | + ----- |
| 148 | + Refer to :class:`pylops.waveeqprocessing.MDD` for implementation |
| 149 | + details. Note that this implementation is currently missing the ``wav`` |
| 150 | + and ``causality_precond=False`` options. |
| 151 | +
|
| 152 | + """ |
| 153 | + nf, ns, nr = G.shape |
| 154 | + nt = d.shape[0] |
| 155 | + if len(d.shape) == 2: |
| 156 | + nv = 1 |
| 157 | + else: |
| 158 | + nv = d.shape[2] |
| 159 | + if twosided: |
| 160 | + if add_negative: |
| 161 | + nt2 = 2 * nt - 1 |
| 162 | + else: |
| 163 | + nt2 = nt |
| 164 | + nt = (nt2 + 1) // 2 |
| 165 | + nfmax_allowed = int(np.ceil((nt2+1)/2)) |
| 166 | + else: |
| 167 | + nt2 = nt |
| 168 | + nfmax_allowed = nt |
| 169 | + |
| 170 | + # Fix nfmax to be at maximum equal to half of the size of fft samples |
| 171 | + if nfmax is None or nfmax > nfmax_allowed: |
| 172 | + nfmax = nfmax_allowed |
| 173 | + logging.warning('nfmax set equal to ceil[(nt+1)/2=%d]' % nfmax) |
| 174 | + |
| 175 | + # Add negative part to data and model |
| 176 | + if twosided and add_negative: |
| 177 | + if nv == 1: |
| 178 | + d = da.concatenate((da.zeros((nt - 1, ns)), d), axis=0) |
| 179 | + else: |
| 180 | + d = da.concatenate((da.zeros((nt - 1, ns, nv)), d), axis=0) |
| 181 | + |
| 182 | + # Define MDC linear operator |
| 183 | + MDCop = MDC(G, nt2, nv=nv, dt=dt, dr=dr, |
| 184 | + twosided=twosided, saveGt=saveGt) |
| 185 | + if dottest: |
| 186 | + Dottest(MDCop, nt2 * ns * nv, nt2 * nr * nv, verb=True) |
| 187 | + |
| 188 | + # Adjoint |
| 189 | + if adjoint: |
| 190 | + madj = MDCop.H * d.flatten() |
| 191 | + madj = da.squeeze(madj.reshape(nt2, nr, nv)) |
| 192 | + |
| 193 | + # Inverse |
| 194 | + minv = cgls(MDCop, d.flatten(), **kwargs_cgls)[0] |
| 195 | + minv = da.squeeze(minv.reshape(nt2, nr, nv)) |
| 196 | + #if wav is not None: |
| 197 | + # minv = sp_convolve1d(minv, wav, axis=-1) |
| 198 | + |
| 199 | + if adjoint: |
| 200 | + return minv, madj |
| 201 | + else: |
| 202 | + return minv |
0 commit comments