Ejemplo n.º 1
0
def compute_Q_v2(G, copy_X=True):
    """Alternative version of compute_Q.

    experimental:  not recommended over compute_Q()
    """
    from mrrt.nufft._nufft import nufft_adj

    ones = np.ones(G.kspace.shape[0], G.Gnufft._cplx_dtype)
    sf = np.sqrt(prod(G.Gnufft.Kd))
    return sf * fftn(nufft_adj(G.Gnufft, ones, copy_X=True, return_psf=True))
Ejemplo n.º 2
0
def test_fft_output_dtype(xp):
    x = xp.random.randn(256)
    y = fftn(x, axes=None, norm="ortho", xp=xp)
    assert_equal(y.dtype, xp.complex128)
    r = ifftn(y, axes=None, norm="ortho", xp=xp)
    assert_equal(r.dtype, xp.complex128)

    x = xp.random.randn(256).astype(np.complex128)
    y = fftn(x, axes=None, norm="ortho", xp=xp)
    assert_equal(y.dtype, xp.complex128)
    r = ifftn(y, axes=None, norm="ortho", xp=xp)
    assert_equal(r.dtype, xp.complex128)

    for dtype in [xp.float16, xp.float32, xp.complex64]:
        x = xp.random.randn(256).astype(dtype)
        y = fftn(x, axes=None, norm="ortho", xp=xp)
        assert_equal(y.dtype, xp.complex64)

        r = ifftn(y, axes=None, norm="ortho", xp=xp)
        assert_equal(r.dtype, xp.complex64)
Ejemplo n.º 3
0
    def norm(self, x):
        # if not hasattr(self, 'Q') or self.Q is None:
        #     warnings.warn("Toeplitz Q did not exist, creating it...")
        #     self.prep_toeplitz()

        x = complexify(x)
        if self.masked:
            x = embed(x, self.mask, order=self.order)
        try:
            if x.size % self.nargin != 0:
                raise ValueError("wrong size input")
            Nrepetitions = x.size // self.nargin
        except IndexError:
            Nrepetitions = 1

        if hasattr(self, "Q"):
            slices = [slice(None)] * x.ndim
            for d in range(len(self.Nd)):
                slices[d] = slice(self.Nd[d])
            if Nrepetitions == 1:
                y = fftn(x, s=self.Q.shape)
                y *= self.Q
                y = ifftn(y)[slices]
            else:
                if self.order == "C":
                    x_shape = (Nrepetitions,) + tuple(self.Nd)
                else:
                    x_shape = tuple(self.Nd) + (Nrepetitions,)
                x = x.reshape(x_shape, order=self.order)
                fft_axes = tuple(np.arange(len(self.Nd)))
                y = fftn(x, s=self.Q.shape, axes=fft_axes)
                y *= self.Q[..., np.newaxis]  # add an axis for repetitions
                y = ifftn(y, axes=fft_axes)[slices]
        else:
            y = self.H * (self * x)
        return y
Ejemplo n.º 4
0
def test_partial_FFT_with_im_mask(xp, nd_in, order, shift):
    """ masked FFT with missing samples and masked image domain """
    c = get_data(xp)
    rstate = xp.random.RandomState(1234)
    sample_mask = rstate.rand(*(128, 127)) > 0.5
    x, y = xp.meshgrid(
        xp.arange(-c.shape[0] // 2, c.shape[0] // 2),
        xp.arange(-c.shape[1] // 2, c.shape[1] // 2),
        indexing="ij",
        sparse=True,
    )

    # make a circular mask
    im_mask = xp.sqrt(x * x + y * y) < c.shape[0] // 2

    nd_out = False
    FTop = FFT_Operator(
        c.shape,
        order=order,
        im_mask=im_mask,
        use_fft_shifts=shift,
        nd_input=nd_in,
        nd_output=nd_out,
        sample_mask=sample_mask,
        gpu_force_reinit=False,
        mask_kspace_on_gpu=(not shift),
        **get_loc(xp),
    )

    # create new linear operator for forward followed by inverse transform
    FtF = FTop.H * FTop
    assert isinstance(FtF, LinearOperatorMulti)

    # test forward only
    forw = embed(FTop * masker(c, im_mask, order=order),
                 sample_mask,
                 order=order)

    if shift:
        expected_forw = sample_mask * fftnc(c * im_mask)
    else:
        expected_forw = sample_mask * fftn(c * im_mask)
    xp.testing.assert_allclose(forw, expected_forw, rtol=1e-7, atol=1e-4)

    # test roundtrip
    roundtrip = FTop.H * (FTop * masker(c, im_mask, order=order))
    if shift:
        expected_roundtrip = masker(ifftnc(sample_mask * fftnc(c * im_mask)),
                                    im_mask,
                                    order=order)
    else:
        expected_roundtrip = masker(ifftn(sample_mask * fftn(c * im_mask)),
                                    im_mask,
                                    order=order)

    xp.testing.assert_allclose(roundtrip,
                               expected_roundtrip,
                               rtol=1e-7,
                               atol=1e-4)

    # test roundtrip with 2 reps
    c2 = xp.stack([c] * 2, axis=-1)
    roundtrip = FTop.H * (FTop * masker(c2, im_mask, order=order))
    if shift:
        expected_roundtrip = masker(
            ifftnc(
                sample_mask[..., xp.newaxis] *
                fftnc(c2 * im_mask[..., xp.newaxis], axes=(0, 1)),
                axes=(0, 1),
            ),
            im_mask,
            order=order,
        )
    else:
        expected_roundtrip = masker(
            ifftn(
                sample_mask[..., xp.newaxis] *
                fftn(c2 * im_mask[..., xp.newaxis], axes=(0, 1)),
                axes=(0, 1),
            ),
            im_mask,
            order=order,
        )
    xp.testing.assert_allclose(roundtrip,
                               expected_roundtrip,
                               rtol=1e-7,
                               atol=1e-4)
Ejemplo n.º 5
0
def compute_Q(G, wi=None, Nd_os=2, Kd_os=1.35, J=5, **extra_nufft_kwargs):
    """Compute Q such that IFFT(Q*FFT(x)) = (G.H * G * x).

    Notes
    -----
    requires that G.Kd ~= 2*G.Nd for good accuracy.
    can get away with Kd_os < substantially less than 2

    References
    ----------
    ..[1] Wajer FTAW, Pruessmann KP. Major Speedup of Reconstruction for
    Sensitivity Encoding with Arbitrary Trajectories.
    Proc. Intl. Soc. Mag. Reson. Med. 9 (2001), p.767.

    ..[2] Eggers H, Boernert P, Boesiger P.  Comparison of Gridding- and
    Convolution-Based Iterative Reconstruction Algorithms For
    Sensitivity-Encoded Non-Cartesian Acquisitions.
    Proc. Intl. Soc. Mag. Reson. Med. 10 (2002)

    ..[3] Liu C, Moseley ME, Bammer R.  Fast SENSE Reconstruction Using Linear
    System Transfer Function.
    Proc. Intl. Soc. Mag. Reson. Med. 13 (2005), p.689.
    """
    from mrrt.mri.operators import MRI_Operator, NUFFT_Operator

    if isinstance(G, NUFFT_Operator):
        Gnufft_op = G
    elif isinstance(G, MRI_Operator):
        Gnufft_op = G.Gnufft
    else:
        raise ValueError("G must be an NUFFT_Operator or MRI_Operator")

    # need reasonably accurate gridding onto a 2x oversampled grid
    Nd = (Nd_os * Gnufft_op.Nd).astype(np.intp)
    Kd = next_fast_len((Kd_os * Nd).astype(np.intp))
    if any(k < 2 * n for (k, n) in zip(G.Kd, G.Nd)):
        warnings.warn(
            "Q operator unlikely to be accurate.  Recommend using G "
            "with a grid oversampling factor of 2"
        )
    if Nd_os != 2:
        warnings.warn("recommend keeping Nd_os=2")

    G2 = NUFFT_Operator(
        omega=Gnufft_op.om,
        Nd=Nd,
        Kd=Kd,
        Jd=(J,) * len(Nd),
        Ld=Gnufft_op.Ld,
        n_shift=Nd / 2,
        mode=Gnufft_op.mode,
        phasing="real",  # ONLY WORKS IF THIS IS REAL!
        **extra_nufft_kwargs,
    )

    if wi is None:
        wi = np.ones(Gnufft_op.om.shape[0], dtype=Gnufft_op._cplx_dtype)

    psft = G2.H * wi
    # TODO: allow DiagonalOperator too for weights
    psft = np.fft.fftshift(psft.reshape(G2.Nd, order=G2.order))
    return fftn(psft)