Exemple #1
0
def test_Radon2D(par):
    """Dot-test and sparse inverse for Radon2D operator
    """
    dt, dh = 0.005, 1
    t = np.arange(par['nt']) * dt
    h = np.arange(par['nhx']) * dh
    px = np.linspace(0, par['pxmax'], par['npx'])
    x = np.zeros((par['npx'], par['nt']))
    x[2, par['nt'] // 2] = 1

    Rop = Radon2D(t,
                  h,
                  px,
                  centeredh=par['centeredh'],
                  interp=par['interp'],
                  kind=par['kind'],
                  onthefly=par['onthefly'],
                  engine=par['engine'],
                  dtype='float64')
    assert dottest(Rop,
                   par['nhx'] * par['nt'],
                   par['npx'] * par['nt'],
                   complexflag=0)
    y = Rop * x.flatten()
    y = y.reshape(par['nhx'], par['nt'])

    xinv, _, _ = FISTA(Rop, y.flatten(), 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.flatten(), xinv, decimal=1)
def test_ISTA_FISTA_unknown_threshkind():
    """Check error is raised if unknown threshkind is passed
    """
    with pytest.raises(NotImplementedError):
        _ = ISTA(Identity(5), np.ones(5), 10, threshkind='foo')
    with pytest.raises(NotImplementedError):
        _ = FISTA(Identity(5), np.ones(5), 10, threshkind='foo')
Exemple #3
0
def test_ChirpRadon3D(par):
    """Dot-test, forward, analytical inverse and sparse inverse
    for ChirpRadon3D operator
    """
    parmod = {
        "ot": 0,
        "dt": 0.004,
        "nt": par["nt"],
        "ox": par["nhx"] * 10 / 2,
        "dx": 10,
        "nx": par["nhx"],
        "oy": par["nhy"] * 10 / 2,
        "dy": 10,
        "ny": par["nhy"],
        "f0": 40,
    }
    theta = [
        20,
    ]
    phi = [
        0,
    ]
    t0 = [
        0.1,
    ]
    amp = [
        1.0,
    ]

    # Create axis
    t, t2, hx, hy = makeaxis(parmod)

    # Create wavelet
    wav, _, wav_c = ricker(t[:41], f0=parmod["f0"])

    # Generate model
    _, x = linear3d(hy, hx, t, 1500.0, t0, theta, phi, amp, wav)
    Rop = ChirpRadon3D(
        t,
        hy,
        hx,
        (par["pymax"], par["pxmax"]),
        engine=par["engine"],
        dtype="float64",
        **dict(flags=("FFTW_ESTIMATE",), threads=2)
    )
    assert dottest(
        Rop, par["nhy"] * par["nhx"] * par["nt"], par["nhy"] * par["nhx"] * par["nt"]
    )

    y = Rop * x.ravel()
    xinvana = Rop.inverse(y)
    assert_array_almost_equal(x.ravel(), xinvana, decimal=3)

    xinv, _, _ = FISTA(Rop, y, 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.ravel(), xinv, decimal=3)
def test_Radon3D(par):
    """Dot-test,  forward and adjoint consistency check
    (for onthefly parameter), and sparse inverse for Radon3D operator
    """
    if par['engine'] == 'numpy' or \
        multiprocessing.cpu_count() >= 4: # avoid timeout in travis for numba

        dt, dhy, dhx = 0.005, 1, 1
        t = np.arange(par['nt']) * dt
        hy = np.arange(par['nhy']) * dhy
        hx = np.arange(par['nhx']) * dhx
        py = np.linspace(0, par['pymax'], par['npy'])
        px = np.linspace(0, par['pxmax'], par['npx'])
        x = np.zeros((par['npy'], par['npx'], par['nt']))
        x[3, 2, par['nt'] // 2] = 1

        Rop = Radon3D(t,
                      hy,
                      hx,
                      py,
                      px,
                      centeredh=par['centeredh'],
                      interp=par['interp'],
                      kind=par['kind'],
                      onthefly=False,
                      engine=par['engine'],
                      dtype='float64')
        R1op = Radon3D(t,
                       hy,
                       hx,
                       py,
                       px,
                       centeredh=par['centeredh'],
                       interp=par['interp'],
                       kind=par['kind'],
                       onthefly=True,
                       engine=par['engine'],
                       dtype='float64')

        assert dottest(Rop,
                       par['nhy'] * par['nhx'] * par['nt'],
                       par['npy'] * par['npx'] * par['nt'],
                       tol=1e-3)
        y = Rop * x.flatten()
        y1 = R1op * x.flatten()
        assert_array_almost_equal(y, y1, decimal=4)

        xadj = Rop.H * y
        xadj1 = R1op.H * y
        assert_array_almost_equal(xadj, xadj1, decimal=4)

        if Rop.engine == 'numba':  # as numpy is too slow here...
            xinv, _, _ = FISTA(Rop, y, 200, eps=3e0, returninfo=True)
            assert_array_almost_equal(x.flatten(), xinv, decimal=1)
def test_ChirpRadon3D(par):
    """Dot-test, forward, analytical inverse and sparse inverse
    for ChirpRadon3D operator
    """
    parmod = {
        'ot': 0,
        'dt': 0.004,
        'nt': par['nt'],
        'ox': par['nhx'] * 10 / 2,
        'dx': 10,
        'nx': par['nhx'],
        'oy': par['nhy'] * 10 / 2,
        'dy': 10,
        'ny': par['nhy'],
        'f0': 40
    }
    theta = [
        20,
    ]
    phi = [
        0,
    ]
    t0 = [
        0.1,
    ]
    amp = [
        1.,
    ]

    # Create axis
    t, t2, hx, hy = makeaxis(parmod)

    # Create wavelet
    wav, _, wav_c = ricker(t[:41], f0=parmod['f0'])

    # Generate model
    _, x = linear3d(hy, hx, t, 1500., t0, theta, phi, amp, wav)
    Rop = ChirpRadon3D(t,
                       hy,
                       hx, (par['pymax'], par['pxmax']),
                       engine=par['engine'],
                       dtype='float64',
                       **dict(flags=('FFTW_ESTIMATE', ), threads=2))
    assert dottest(Rop, par['nhy'] * par['nhx'] * par['nt'],
                   par['nhy'] * par['nhx'] * par['nt'])

    y = Rop * x.ravel()
    xinvana = Rop.inverse(y)
    assert_array_almost_equal(x.ravel(), xinvana, decimal=3)

    xinv, _, _ = FISTA(Rop, y, 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.ravel(), xinv, decimal=3)
def test_ISTA_FISTA_missing_perc():
    """Check error is raised if perc=None and threshkind is percentile based
    """
    with pytest.raises(ValueError):
        _ = ISTA(Identity(5),
                 np.ones(5),
                 10,
                 perc=None,
                 threshkind='soft-percentile')
    with pytest.raises(ValueError):
        _ = FISTA(Identity(5),
                  np.ones(5),
                  10,
                  perc=None,
                  threshkind='soft-percentile')
Exemple #7
0
def test_ISTA_FISTA(par):
    """Invert problem with ISTA/FISTA
    """
    np.random.seed(42)
    Aop = MatrixMult(np.random.randn(par['ny'], par['nx']))

    x = np.zeros(par['nx'])
    x[par['nx'] // 2] = 1
    x[3] = 1
    x[par['nx'] - 4] = -1
    y = Aop * x

    eps = 0.5
    maxit = 2000

    # ISTA with too high alpha (check that exception is raised)
    with pytest.raises(ValueError):
        xinv, _, _ = ISTA(Aop,
                          y,
                          maxit,
                          eps=eps,
                          alpha=1e5,
                          monitorres=True,
                          tol=0,
                          returninfo=True)

    # ISTA
    xinv, _, _ = ISTA(Aop,
                      y,
                      maxit,
                      eps=eps,
                      tol=0,
                      returninfo=True,
                      show=False)
    assert_array_almost_equal(x, xinv, decimal=1)

    # FISTA
    xinv, _, _ = FISTA(Aop,
                       y,
                       maxit,
                       eps=eps,
                       tol=0,
                       returninfo=True,
                       show=False)
    assert_array_almost_equal(x, xinv, decimal=1)
Exemple #8
0
def test_Radon2D(par):
    """Dot-test, forward and adjoint consistency check
    (for onthefly parameter), and sparse inverse for Radon2D operator
    """
    dt, dh = 0.005, 1
    t = np.arange(par["nt"]) * dt
    h = np.arange(par["nhx"]) * dh
    px = np.linspace(0, par["pxmax"], par["npx"])
    x = np.zeros((par["npx"], par["nt"]))
    x[2, par["nt"] // 2] = 1

    Rop = Radon2D(
        t,
        h,
        px,
        centeredh=par["centeredh"],
        interp=par["interp"],
        kind=par["kind"],
        onthefly=False,
        engine=par["engine"],
        dtype="float64",
    )
    R1op = Radon2D(
        t,
        h,
        px,
        centeredh=par["centeredh"],
        interp=par["interp"],
        kind=par["kind"],
        onthefly=True,
        engine=par["engine"],
        dtype="float64",
    )
    assert dottest(Rop, par["nhx"] * par["nt"], par["npx"] * par["nt"], tol=1e-3)

    y = Rop * x.ravel()
    y1 = R1op * x.ravel()
    assert_array_almost_equal(y, y1, decimal=4)

    xadj = Rop.H * y
    xadj1 = R1op.H * y
    assert_array_almost_equal(xadj, xadj1, decimal=4)

    xinv, _, _ = FISTA(Rop, y, 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.ravel(), xinv, decimal=1)
Exemple #9
0
def test_ChirpRadon2D(par):
    """Dot-test, forward, analytical inverse and sparse inverse
    for ChirpRadon2D operator
    """
    parmod = {
        "ot": 0,
        "dt": 0.004,
        "nt": par["nt"],
        "ox": par["nhx"] * 10 / 2,
        "dx": 10,
        "nx": par["nhx"],
        "f0": 40,
    }
    theta = [
        20,
    ]
    t0 = [
        0.1,
    ]
    amp = [
        1.0,
    ]

    # Create axis
    t, t2, hx, _ = makeaxis(parmod)

    # Create wavelet
    wav, _, wav_c = ricker(t[:41], f0=parmod["f0"])

    # Generate model
    _, x = linear2d(hx, t, 1500.0, t0, theta, amp, wav)

    Rop = ChirpRadon2D(t, hx, par["pxmax"], dtype="float64")
    assert dottest(Rop, par["nhx"] * par["nt"], par["nhx"] * par["nt"])

    y = Rop * x.ravel()
    xinvana = Rop.inverse(y)
    assert_array_almost_equal(x.ravel(), xinvana, decimal=3)

    xinv, _, _ = FISTA(Rop, y, 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.ravel(), xinv, decimal=3)
def test_ChirpRadon2D(par):
    """Dot-test, forward, analytical inverse and sparse inverse
    for ChirpRadon2D operator
    """
    parmod = {
        'ot': 0,
        'dt': 0.004,
        'nt': par['nt'],
        'ox': par['nhx'] * 10 / 2,
        'dx': 10,
        'nx': par['nhx'],
        'f0': 40
    }
    theta = [
        20,
    ]
    t0 = [
        0.1,
    ]
    amp = [
        1.,
    ]

    # Create axis
    t, t2, hx, _ = makeaxis(parmod)

    # Create wavelet
    wav, _, wav_c = ricker(t[:41], f0=parmod['f0'])

    # Generate model
    _, x = linear2d(hx, t, 1500., t0, theta, amp, wav)

    Rop = ChirpRadon2D(t, hx, par['pxmax'], dtype='float64')
    assert dottest(Rop, par['nhx'] * par['nt'], par['nhx'] * par['nt'])

    y = Rop * x.ravel()
    xinvana = Rop.inverse(y)
    assert_array_almost_equal(x.ravel(), xinvana, decimal=3)

    xinv, _, _ = FISTA(Rop, y, 30, eps=1e0, returninfo=True)
    assert_array_almost_equal(x.ravel(), xinv, decimal=3)
Exemple #11
0
def test_Radon3D(par):
    """Dot-test and sparse inverse for Radon3D operator
    """
    if par['engine'] == 'numpy' or \
        multiprocessing.cpu_count() >= 4: # avoid timeout in travis for numba

        dt, dhy, dhx = 0.005, 1, 1
        t = np.arange(par['nt']) * dt
        hy = np.arange(par['nhy']) * dhy
        hx = np.arange(par['nhx']) * dhx
        py = np.linspace(0, par['pymax'], par['npy'])
        px = np.linspace(0, par['pxmax'], par['npx'])
        x = np.zeros((par['npy'], par['npx'], par['nt']))
        x[3, 2, par['nt'] // 2] = 1

        Rop = Radon3D(t,
                      hy,
                      hx,
                      py,
                      px,
                      centeredh=par['centeredh'],
                      interp=par['interp'],
                      kind=par['kind'],
                      onthefly=par['onthefly'],
                      engine=par['engine'],
                      dtype='float64')
        assert dottest(Rop,
                       par['nhy'] * par['nhx'] * par['nt'],
                       par['npy'] * par['npx'] * par['nt'],
                       complexflag=0)
        if Rop.engine == 'numba' and Rop.usetable == True:  # as numpy is too slow here...
            y = Rop * x.flatten()
            y = y.reshape(par['nhy'], par['nhx'], par['nt'])

            xinv, _, _ = FISTA(Rop, y.flatten(), 200, eps=3e0, returninfo=True)
            assert_array_almost_equal(x.flatten(), xinv, decimal=1)
def SeismicInterpolation(data,
                         nrec,
                         iava,
                         iava1=None,
                         kind='fk',
                         nffts=None,
                         sampling=None,
                         spataxis=None,
                         spat1axis=None,
                         taxis=None,
                         paxis=None,
                         p1axis=None,
                         centeredh=True,
                         nwins=None,
                         nwin=None,
                         nover=None,
                         design=False,
                         engine='numba',
                         dottest=False,
                         **kwargs_solver):
    r"""Seismic interpolation (or regularization).

    Interpolate seismic data from irregular to regular spatial grid.
    Depending on the size of the input ``data``, interpolation is either
    2- or 3-dimensional. In case of 3-dimensional interpolation,
    data can be irregularly sampled in either one or both spatial directions.

    Parameters
    ----------
    data : :obj:`np.ndarray`
        Irregularly sampled seismic data of size
        :math:`[n_{r_y} (\times n_{r_x} \times n_t)]`
    nrec : :obj:`int` or :obj:`tuple`
        Number of elements in the regularly sampled (reconstructed) spatial
        array, :math:`n_{R_y}` for 2-dimensional data and
        :math:`(n_{R_y}, n_{R_x})` for 3-dimensional data
    iava : :obj:`list` or :obj:`numpy.ndarray`
        Integer (or floating) indices of locations of available samples in
        first dimension of regularly sampled spatial grid of interpolated
        signal. The :class:`pylops.basicoperators.Restriction` operator is
        used in case of integer indices, while the
        :class:`pylops.signalprocessing.Iterp` operator is used in
        case of floating indices.
    iava1 : :obj:`list` or :obj:`numpy.ndarray`, optional
        Integer (or floating) indices of locations of available samples in
        second dimension of regularly sampled spatial grid of interpolated
        signal. Can be used only in case of 3-dimensional data.
    kind : :obj:`str`, optional
        Type of inversion: ``fk`` (default), ``spatial``, ``radon-linear``,
        ``chirpradon-linear``, ``radon-parabolic`` or , ``radon-hyperbolic``
        and ``sliding``
    nffts : :obj:`int` or :obj:`tuple`, optional
        nffts : :obj:`tuple`, optional
        Number of samples in Fourier Transform for each direction.
        Required if ``kind='fk'``
    sampling : :obj:`tuple`, optional
        Sampling steps ``dy`` (, ``dx``) and ``dt``. Required if ``kind='fk'``
        or ``kind='radon-linear'``
    spataxis : :obj:`np.ndarray`, optional
        First spatial axis. Required for ``kind='radon-linear'``,
        ``kind='chirpradon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'``, can also be provided instead of
        ``sampling`` for ``kind='fk'``
    spat1axis : :obj:`np.ndarray`, optional
        Second spatial axis. Required for ``kind='radon-linear'``,
        ``kind='chirpradon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'``, can also be provided instead of
        ``sampling`` for ``kind='fk'``
    taxis : :obj:`np.ndarray`, optional
        Time axis. Required for ``kind='radon-linear'``,
        ``kind='chirpradon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'``, can also be provided instead of
        ``sampling`` for ``kind='fk'``
    paxis : :obj:`np.ndarray`, optional
        First Radon axis. Required for ``kind='radon-linear'``,
        ``kind='chirpradon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'`` and ``kind='sliding'``
    p1axis : :obj:`np.ndarray`, optional
        Second Radon axis. Required for ``kind='radon-linear'``,
        ``kind='chirpradon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'`` and ``kind='sliding'``
    centeredh : :obj:`bool`, optional
        Assume centered spatial axis (``True``) or not (``False``).
        Required for ``kind='radon-linear'``, ``kind='radon-parabolic'``
        and ``kind='radon-hyperbolic'``
    nwins : :obj:`int` or :obj:`tuple`, optional
        Number of windows. Required for ``kind='sliding'``
    nwin : :obj:`int` or :obj:`tuple`, optional
        Number of samples of window. Required for ``kind='sliding'``
    nover : :obj:`int` or :obj:`tuple`, optional
        Number of samples of overlapping part of window. Required for
        ``kind='sliding'``
    design : :obj:`bool`, optional
        Print number of sliding window (``True``) or not (``False``) when
        using ``kind='sliding'``
    engine : :obj:`str`, optional
        Engine used for Radon computations (``numpy/numba``
        for ``Radon2D`` and ``Radon3D`` or ``numpy/fftw``
        for ``ChirpRadon2D`` and ``ChirpRadon3D`` or )
    dottest : :obj:`bool`, optional
        Apply dot-test
    **kwargs_solver
        Arbitrary keyword arguments for
        :py:func:`pylops.optimization.leastsquares.RegularizedInversion` solver
        if ``kind='spatial'`` or
        :py:func:`pylops.optimization.sparsity.FISTA` solver otherwise

    Returns
    -------
    recdata : :obj:`np.ndarray`
        Reconstructed data of size :math:`[n_{R_y} (\times n_{R_x} \times n_t)]`
    recprec : :obj:`np.ndarray`
        Reconstructed data in the sparse or preconditioned domain in case of
        ``kind='fk'``, ``kind='radon-linear'``, ``kind='radon-parabolic'``,
        ``kind='radon-hyperbolic'`` and ``kind='sliding'``
    cost : :obj:`np.ndarray`
        Cost function norm

    Raises
    ------
    KeyError
        If ``kind`` is neither ``spatial``, ``fl``, ``radon-linear``,
        ``radon-parabolic``, ``radon-hyperbolic`` nor ``sliding``

    Notes
    -----
    The problem of seismic data interpolation (or regularization) can be
    formally written as

    .. math::
        \mathbf{y} = \mathbf{R} \mathbf{x}

    where a restriction or interpolation operator is applied along the spatial
    direction(s). Here :math:`\mathbf{y} = [\mathbf{y}_{R1}^T, \mathbf{y}_{R2}^T,...,
    \mathbf{y}_{RN^T}]^T` where each vector :math:`\mathbf{y}_{Ri}`
    contains all time samples recorded in the seismic data at the specific
    receiver :math:`R_i`. Similarly, :math:`\mathbf{x} = [\mathbf{x}_{r1}^T,
    \mathbf{x}_{r2}^T,..., \mathbf{x}_{rM}^T]`, contains all traces at the
    regularly and finely sampled receiver locations :math:`r_i`.

    Several alternative approaches can be taken to solve such a problem. They
    mostly differ in the choice of the regularization (or preconditining) used
    to mitigate the ill-posedness of the problem:

        * ``spatial``: least-squares inversion in the original time-space domain
          with an additional spatial smoothing regularization term,
          corresponding to the cost function
          :math:`J = ||\mathbf{y} - \mathbf{R} \mathbf{x}||_2 +
          \epsilon_\nabla \nabla ||\mathbf{x}||_2` where :math:`\nabla` is
          a second order space derivative implemented via
          :class:`pylops.basicoperators.SecondDerivative` in 2-dimensional case
          and :class:`pylops.basicoperators.Laplacian` in 3-dimensional case
        * ``fk``: L1 inversion in frequency-wavenumber preconditioned domain
          corresponding to the cost function
          :math:`J = ||\mathbf{y} - \mathbf{R} \mathbf{F} \mathbf{x}||_2` where
          :math:`\mathbf{F}` is frequency-wavenumber transform implemented via
          :class:`pylops.signalprocessing.FFT2D` in 2-dimensional case
          and :class:`pylops.signalprocessing.FFTND` in 3-dimensional case
        * ``radon-linear``: L1 inversion in linear Radon preconditioned domain
          using the same cost function as ``fk`` but with :math:`\mathbf{F}`
          being a Radon transform implemented via
          :class:`pylops.signalprocessing.Radon2D` in 2-dimensional case
          and :class:`pylops.signalprocessing.Radon3D` in 3-dimensional case
        * ``radon-parabolic``: L1 inversion in parabolic Radon
          preconditioned domain
        * ``radon-hyperbolic``: L1 inversion in hyperbolic Radon
          preconditioned domain
        * ``sliding``: L1 inversion in sliding-linear Radon
          preconditioned domain using the same cost function as ``fk``
          but with :math:`\mathbf{F}` being a sliding Radon transform
          implemented via :class:`pylops.signalprocessing.Sliding2D` in
          2-dimensional case and :class:`pylops.signalprocessing.Sliding3D`
          in 3-dimensional case

    """
    ncp = get_array_module(data)

    dtype = data.dtype
    ndims = data.ndim
    if ndims == 1 or ndims > 3:
        raise ValueError('data must have 2 or 3 dimensions')
    if ndims == 2:
        dimsd = data.shape
        dims = (nrec, dimsd[1])
    else:
        dimsd = data.shape
        dims = (nrec[0], nrec[1], dimsd[2])

    # sampling
    if taxis is not None:
        dt = taxis[1] - taxis[0]
    if spataxis is not None:
        dspat = np.abs(spataxis[1] - spataxis[0])
    if spat1axis is not None:
        dspat1 = np.abs(spat1axis[1] - spat1axis[0])

    # create restriction/interpolation operator
    if iava.dtype == float:
        Rop = Interp(np.prod(dims),
                     iava,
                     dims=dims,
                     dir=0,
                     kind='linear',
                     dtype=dtype)
        if ndims == 3 and iava1 is not None:
            dims1 = (len(iava), nrec[1], dimsd[2])
            Rop1 = Interp(np.prod(dims1),
                          iava1,
                          dims=dims1,
                          dir=1,
                          kind='linear',
                          dtype=dtype)
            Rop = Rop1 * Rop
    else:
        Rop = Restriction(np.prod(dims), iava, dims=dims, dir=0, dtype=dtype)
        if ndims == 3 and iava1 is not None:
            dims1 = (len(iava), nrec[1], dimsd[2])
            Rop1 = Restriction(np.prod(dims1),
                               iava1,
                               dims=dims1,
                               dir=1,
                               dtype=dtype)
            Rop = Rop1 * Rop

    # create other operators for inversion
    if kind == 'spatial':
        prec = False
        dotcflag = 0
        if ndims == 3 and iava1 is not None:
            Regop = Laplacian(dims=dims, dirs=(0, 1), dtype=dtype)
        else:
            Regop = SecondDerivative(np.prod(dims),
                                     dims=(dims),
                                     dir=0,
                                     dtype=dtype)
        SIop = Rop
    elif kind == 'fk':
        prec = True
        dimsp = nffts
        dotcflag = 1
        if ndims == 3:
            if sampling is None:
                if spataxis is None or spat1axis is None or taxis is None:
                    raise ValueError('Provide either sampling or spataxis, '
                                     'spat1axis and taxis for kind=%s' % kind)
                else:
                    sampling = (np.abs(spataxis[1] - spataxis[1]),
                                np.abs(spat1axis[1] - spat1axis[1]),
                                np.abs(taxis[1] - taxis[1]))
            Pop = FFTND(dims=dims, nffts=nffts, sampling=sampling)
            Pop = Pop.H
        else:
            if sampling is None:
                if spataxis is None or taxis is None:
                    raise ValueError('Provide either sampling or spataxis, '
                                     'and taxis for kind=%s' % kind)
                else:
                    sampling = (np.abs(spataxis[1] - spataxis[1]),
                                np.abs(taxis[1] - taxis[1]))
            Pop = FFT2D(dims=dims, nffts=nffts, sampling=sampling)
            Pop = Pop.H
        SIop = Rop * Pop
    elif 'chirpradon' in kind:
        prec = True
        dotcflag = 0
        if ndims == 3:
            Pop = ChirpRadon3D(
                taxis, spataxis, spat1axis,
                (np.max(paxis) * dspat / dt, np.max(p1axis) * dspat1 / dt)).H
            dimsp = (spataxis.size, spat1axis.size, taxis.size)
        else:
            Pop = ChirpRadon2D(taxis, spataxis, np.max(paxis) * dspat / dt).H
            dimsp = (spataxis.size, taxis.size)
        SIop = Rop * Pop
    elif 'radon' in kind:
        prec = True
        dotcflag = 0
        kindradon = kind.split('-')[-1]
        if ndims == 3:
            Pop = Radon3D(taxis,
                          spataxis,
                          spat1axis,
                          paxis,
                          p1axis,
                          centeredh=centeredh,
                          kind=kindradon,
                          engine=engine)
            dimsp = (paxis.size, p1axis.size, taxis.size)

        else:
            Pop = Radon2D(taxis,
                          spataxis,
                          paxis,
                          centeredh=centeredh,
                          kind=kindradon,
                          engine=engine)
            dimsp = (paxis.size, taxis.size)
        SIop = Rop * Pop
    elif kind == 'sliding':
        prec = True
        dotcflag = 0
        if ndims == 3:
            nspat, nspat1 = spataxis.size, spat1axis.size
            spataxis_local = np.linspace(-dspat * nwin[0] // 2,
                                         dspat * nwin[0] // 2, nwin[0])
            spat1axis_local = np.linspace(-dspat1 * nwin[1] // 2,
                                          dspat1 * nwin[1] // 2, nwin[1])
            dimsslid = (nspat, nspat1, taxis.size)
            if ncp == np:
                npaxis, np1axis = paxis.size, p1axis.size
                Op = Radon3D(taxis,
                             spataxis_local,
                             spat1axis_local,
                             paxis,
                             p1axis,
                             centeredh=True,
                             kind='linear',
                             engine=engine)
            else:
                npaxis, np1axis = nwin[0], nwin[1]
                Op = ChirpRadon3D(taxis, spataxis_local, spat1axis_local,
                                  (np.max(paxis) * dspat / dt,
                                   np.max(p1axis) * dspat1 / dt)).H
            dimsp = (nwins[0] * npaxis, nwins[1] * np1axis, dimsslid[2])
            Pop = Sliding3D(Op,
                            dimsp,
                            dimsslid,
                            nwin,
                            nover, (npaxis, np1axis),
                            tapertype='cosine')
            # to be able to reshape correctly the preconditioned model
            dimsp = (nwins[0], nwins[1], npaxis, np1axis, dimsslid[2])
        else:
            nspat = spataxis.size
            spataxis_local = np.linspace(-dspat * nwin // 2, dspat * nwin // 2,
                                         nwin)
            dimsslid = (nspat, taxis.size)
            if ncp == np:
                npaxis = paxis.size
                Op = Radon2D(taxis,
                             spataxis_local,
                             paxis,
                             centeredh=True,
                             kind='linear',
                             engine=engine)
            else:
                npaxis = nwin
                Op = ChirpRadon2D(taxis, spataxis_local,
                                  np.max(paxis) * dspat / dt).H
            dimsp = (nwins * npaxis, dimsslid[1])
            Pop = Sliding2D(Op,
                            dimsp,
                            dimsslid,
                            nwin,
                            nover,
                            tapertype='cosine',
                            design=design)
        SIop = Rop * Pop
    else:
        raise KeyError('kind must be spatial, fk, radon-linear, '
                       'radon-parabolic, radon-hyperbolic or sliding')

    # dot-test
    if dottest:
        Dottest(SIop,
                np.prod(dimsd),
                np.prod(dimsp) if prec else np.prod(dims),
                complexflag=dotcflag,
                raiseerror=True,
                verb=True)

    # inversion
    if kind == 'spatial':
        recdata = \
            RegularizedInversion(SIop, [Regop], data.flatten(),
                                 **kwargs_solver)
        if isinstance(recdata, tuple):
            recdata = recdata[0]
        recdata = recdata.reshape(dims)
        recprec = None
        cost = None
    else:
        recprec = FISTA(SIop, data.flatten(), **kwargs_solver)
        if len(recprec) == 3:
            cost = recprec[2]
        else:
            cost = None
        recprec = recprec[0]
        recdata = np.real(Pop * recprec)

        recprec = recprec.reshape(dimsp)
        recdata = recdata.reshape(dims)

    return recdata, recprec, cost
Exemple #13
0
fig.colorbar(him, ax=ax)
ax.axis('tight')

#%% Create the blurred image and apply the deblurred operator

Cop = Convolve2D(Nz * Nx, h=h,
                 offset=(nh[0] // 2,
                         nh[1] // 2),
                 dims=(Nz, Nx), dtype='float32')
Wop = DWT2D((Nz, Nx), wavelet='haar', level=5)

imblur = Cop * im.flatten()

imdeblur = NormalEquationsInversion(Cop, None, imblur, maxiter=50)

imdeblurl1 = FISTA(Cop * Wop.H, imblur, eps=1e-1, niter=200, show=True)[0]
imdeblurl1 = Wop.H * imdeblurl1

imblur = imblur.reshape(Nz, Nx)
imdeblur = imdeblur.reshape(Nz, Nx)
imdeblurl1 = imdeblurl1.reshape(Nz, Nx)

#%% Display

fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4, figsize=(20, 5))
ax1.imshow(im, cmap='gray', vmin=0, vmax=250)
ax1.axis('tight')
ax1.set_title('Original')
ax2.imshow(imblur, cmap='gray', vmin=0, vmax=250)
ax2.axis('tight')
ax2.set_title('Blurred');
def test_ISTA_FISTA(par):
    """Invert problem with ISTA/FISTA
    """
    np.random.seed(42)
    Aop = MatrixMult(np.random.randn(par['ny'], par['nx']))

    x = np.zeros(par['nx'])
    x[par['nx'] // 2] = 1
    x[3] = 1
    x[par['nx'] - 4] = -1
    y = Aop * x

    eps = 0.5
    perc = 30
    maxit = 2000

    # ISTA with too high alpha (check that exception is raised)
    with pytest.raises(ValueError):
        xinv, _, _ = ISTA(Aop,
                          y,
                          maxit,
                          eps=eps,
                          alpha=1e5,
                          monitorres=True,
                          tol=0,
                          returninfo=True)

    # Regularization based ISTA and FISTA
    for threshkind in ['hard', 'soft', 'half']:
        # ISTA
        xinv, _, _ = ISTA(Aop,
                          y,
                          maxit,
                          eps=eps,
                          threshkind=threshkind,
                          tol=0,
                          returninfo=True,
                          show=False)
        assert_array_almost_equal(x, xinv, decimal=1)

        # FISTA
        xinv, _, _ = FISTA(Aop,
                           y,
                           maxit,
                           eps=eps,
                           threshkind=threshkind,
                           tol=0,
                           returninfo=True,
                           show=False)
        assert_array_almost_equal(x, xinv, decimal=1)

    # Percentile based ISTA and FISTA
    for threshkind in [
            'hard-percentile', 'soft-percentile', 'half-percentile'
    ]:
        # ISTA
        xinv, _, _ = ISTA(Aop,
                          y,
                          maxit,
                          perc=perc,
                          threshkind=threshkind,
                          tol=0,
                          returninfo=True,
                          show=False)
        assert_array_almost_equal(x, xinv, decimal=1)

        # FISTA
        xinv, _, _ = FISTA(Aop,
                           y,
                           maxit,
                           perc=perc,
                           threshkind=threshkind,
                           tol=0,
                           returninfo=True,
                           show=False)
        assert_array_almost_equal(x, xinv, decimal=1)
Exemple #15
0
def test_Radon3D(par):
    """Dot-test,  forward and adjoint consistency check
    (for onthefly parameter), and sparse inverse for Radon3D operator
    """
    if (
        par["engine"] == "numpy" or multiprocessing.cpu_count() >= 4
    ):  # avoid timeout in travis for numba

        dt, dhy, dhx = 0.005, 1, 1
        t = np.arange(par["nt"]) * dt
        hy = np.arange(par["nhy"]) * dhy
        hx = np.arange(par["nhx"]) * dhx
        py = np.linspace(0, par["pymax"], par["npy"])
        px = np.linspace(0, par["pxmax"], par["npx"])
        x = np.zeros((par["npy"], par["npx"], par["nt"]))
        x[3, 2, par["nt"] // 2] = 1

        Rop = Radon3D(
            t,
            hy,
            hx,
            py,
            px,
            centeredh=par["centeredh"],
            interp=par["interp"],
            kind=par["kind"],
            onthefly=False,
            engine=par["engine"],
            dtype="float64",
        )
        R1op = Radon3D(
            t,
            hy,
            hx,
            py,
            px,
            centeredh=par["centeredh"],
            interp=par["interp"],
            kind=par["kind"],
            onthefly=True,
            engine=par["engine"],
            dtype="float64",
        )

        assert dottest(
            Rop,
            par["nhy"] * par["nhx"] * par["nt"],
            par["npy"] * par["npx"] * par["nt"],
            tol=1e-3,
        )
        y = Rop * x.ravel()
        y1 = R1op * x.ravel()
        assert_array_almost_equal(y, y1, decimal=4)

        xadj = Rop.H * y
        xadj1 = R1op.H * y
        assert_array_almost_equal(xadj, xadj1, decimal=4)

        if Rop.engine == "numba":  # as numpy is too slow here...
            xinv, _, _ = FISTA(Rop, y, 200, eps=3e0, returninfo=True)
            assert_array_almost_equal(x.ravel(), xinv, decimal=1)