Source code for snake.core.engine.utils
"""Utilities for the MRD format."""
from copy import deepcopy
import scipy as sp
import numpy as np
from numpy.typing import NDArray
from ..phantom import Phantom, DynamicData
from ..simulation import SimConfig
[docs]
def get_phantom_state(
phantom: Phantom,
dyn_datas: list[DynamicData],
i: int,
sim_conf: SimConfig,
aggregate: bool = True,
) -> [NDArray, NDArray]:
"""Get phantom state after applying all temporal variation."""
frame_phantom = deepcopy(phantom)
for dyn_data in dyn_datas:
frame_phantom = dyn_data.func(frame_phantom, dyn_data.data, i)
frame_phantom = frame_phantom.resample(
new_affine=sim_conf.fov.affine,
new_shape=sim_conf.shape,
use_gpu=True,
)
return (
frame_phantom.contrast(
sim_conf=sim_conf,
resample=False,
aggregate=aggregate,
),
frame_phantom.smaps,
)
[docs]
def fft(image: NDArray, axis: tuple[int, ...] | int = -1) -> NDArray:
"""Apply the FFT operator.
Parameters
----------
image : array
Image in space.
axis : int
Axis to apply the FFT.
Returns
-------
kspace_data : array
kspace data.
"""
return sp.fft.ifftshift(
sp.fft.fftn(sp.fft.fftshift(image, axes=axis), norm="ortho", axes=axis),
axes=axis,
)
[docs]
def get_noise(chunk_data: NDArray, cov: NDArray, rng: np.random.Generator) -> NDArray:
"""Generate noise for a given chunk of k-space data."""
n_coils = cov.shape[0]
chunk_size, n_coils, *xyz = chunk_data.shape
noise_shape = (2, *xyz[::-1], chunk_size)
noise = np.ascontiguousarray(
rng.multivariate_normal(np.zeros(n_coils), cov, size=noise_shape).T,
dtype=np.float32,
)
noise = noise.view(np.complex64)
noise = noise[..., 0]
noise = np.moveaxis(noise, 1, 0)
return noise