Conventions#
Shapes and axes#
Python shapes are C order. The BART dimension vector is the reversed shape:
Data |
Python shape |
BART dimensions |
|---|---|---|
Cartesian coil k-space |
|
|
Radial trajectory |
|
|
Radial coil samples |
|
|
Keep meaningful singleton axes when calling BART’s applications: BART’s coil
dimension is always dimension 3, and sets of maps occupy dimension 4. Inspect
returned shapes rather than assuming every singleton is removed. Compact
shapes such as (coils, y, x) work in explicitly constructed operators; they do
not move the coil dimension in BART’s commands. Use squeeze() for display,
after reconstruction.
Axis arguments are indices, negative ones included:
bartorch.fft(x, axes=(-2, -1)), and no argument takes a BART bitmask. A
set of indices that are not axes – coil channels, parameter maps – is a
tuple of indices too. Regularization is a list of bartorch.prox terms,
never a -R string: pics(..., regularizers=prox.Wavelet((-1, -2), 0.005)).
A command that reads no array, such as seq, counts axes from the last one
and takes negative axes only. Trajectories carry kx, ky, kz in grid units,
not radians or cycles per metre.
Tools and operators#
Functions take and return tensors. Array inputs become contiguous complex64,
and a command works on a copy of each input by default, because some BART
commands write into their inputs; bartorch.set_copy_inputs(False) hands them
the tensor’s own memory.
A LinearOperator has a forward, an adjoint and a
normal, composes with @ and +, and is solved by the classes in
bartorch.optim. P @ F @ S applies sensitivities, then the Fourier
transform, then sampling. FromTorch gives BART’s
Gauss-Newton solver a PyTorch signal model with its derivatives.
FFT is centred and unitary by default;
bartorch.fft() is centred and unnormalized unless unitary=True. State
centring and normalization when comparing reconstructions.
Autograd#
Applying an operator to a tensor that requires a gradient records it, and the
backward pass is the adjoint: for complex tensors, the conjugate Wirtinger
gradient torch expects. A nonlinear operator’s backward pass is the adjoint of
its derivative at the evaluated point. BART’s commands and solvers
(bartorch.tools, bartorch.optim) record nothing, so no gradient
flows through a BART reconstruction or solve.
CFL files#
bartorch.io.readcfl() and bartorch.io.writecfl() use BART’s axis
order, the reverse of a tensor’s. Reverse the axes at that boundary:
import numpy as np
import torch
from bartorch.io import readcfl, writecfl
bart_array = readcfl("kspace") # basename, without .cfl or .hdr
tensor = torch.from_numpy(np.ascontiguousarray(bart_array.T))
writecfl("result", tensor.detach().cpu().numpy().T)
For NumPy arrays, .T reverses all axes. These read and write existing
files; calls between functions pass tensors in memory.