Source code for deepmr._vobj.fields.b0
"""B0 field maps generation routines."""
__all__ = ["b0field"]
import numpy as np
import torch
from ... import fft
[docs]def b0field(chi, b0range=(-200, 200), mask=None):
"""
Simulate inhomogeneous B0 fields.
Output field units is ``[Hz]``. The field
is created by convolving the dipole kernel with an input
magnetic susceptibility map.
Parameters
----------
chi : np.ndarray | torch.Tensor
Object magnetic susceptibility map in ``[ppb]`` of
shape ``(ny, nx)`` (2D) or ``(nz, ny, nx)`` (3D).
b0range : Iterable[float]
Range of B0 field in ``[Hz]``. The default is ``(-200, 200)``.
mask : np.ndarray | torch.Tensor, optional
Region of support of the object of
shape ``(ny, nx)`` (2D) or ``(nz, ny, nx)`` (3D).
The default is ``None``.
Returns
-------
B0map : torch.Tensor
Spatially varying B0 maps of shape ``(ny, nx)`` (2D)
or ``(nz, ny, nx)`` (3D) in ``[Hz]``, arising from the object susceptibility.
Example
-------
>>> import deepmr
We can generate a 2D B0 field map of shape ``(ny=128, nx=128)`` starting from a
magnetic susceptibility distribution:
>>> chi = deepmr.shepp_logan(128, qmr=True)["chi"]
>>> b0map = deepmr.b0field(chi)
B0 values range can be specified using ``b0range`` argument:
>>> b0map = deepmr.b0field(chi, b0range=(-500, 500))
"""
# make sure this is a torch tensor
chi = torch.as_tensor(chi, dtype=torch.float32)
# get input shape
ishape = chi.shape
# get k space coordinates
kgrid = [
np.arange(-ishape[n] // 2, ishape[n] // 2, dtype=np.float32)
for n in range(len(ishape))
]
kgrid = np.meshgrid(*kgrid, indexing="ij")
kgrid = np.stack(kgrid, axis=-1)
knorm = (kgrid**2).sum(axis=-1) + np.finfo(np.float32).eps
dipole_kernel = 1 / 3 - (kgrid[..., 0] ** 2 / knorm)
dipole_kernel = torch.as_tensor(dipole_kernel, dtype=torch.float32)
# apply convolution
B0map = fft.ifft(dipole_kernel * fft.fft(chi)).real
# rescale
B0map = B0map - B0map.min() # (min, max) -> (0, max - min)
B0map = B0map / B0map.max() # (0, max - min) -> (0, 1)
B0map = (
B0map * (b0range[1] - b0range[0]) + b0range[0]
) # (0, 1) -> (b0range[0], b0range[1])
# mask
if mask is not None:
mask = torch.as_tensor(mask != 0)
B0map = mask * B0map
return torch.as_tensor(B0map, dtype=torch.float32)