bart fmac#
=================================================================================================================
The bart fmac command in BART performs element-wise multiplication and summation over specified dimensions, which is particularly useful for operations like applying coil sensitivity maps to k-space data.
Where we can view the full usage string and optional arguments with the -h flag.
!bart fmac -h
Usage: fmac [-A] [-C] [-s d] <input1> [<input2>] <output>
Multiply <input1> and <input2> and accumulate in <output>.
If <input2> is not specified, assume all-ones.
-A add to existing output (instead of overwriting)
-C conjugate input2
-s b squash dimensions selected by bitmask b
-h help
How bart fmac work#
Element-wise Multiplication#
When both input tensors A and B have the same dimensions, fmac performs element-wise multiplication:
Example:#
Given two matrices:
The element-wise multiplication produces:
s: Squashing a Dimension#
If we squash the first dimension (b = 1 in binary: 0001), fmac sums over rows:
Squashing the Second Dimension (-s 2)#
If we squash the second dimension (b = 2 in binary: 0010), fmac sums over columns:
This results in a 1D column vector:
Full Summation (-s 3)#
If b = 3 (binary 0011), it squashes both dimensions, resulting in a single scalar:
For Mismatched Dimensions with Singleton dimension#
If B has a singleton dimension (one column instead of two), fmac will loop over the missing dimension:
Since B has only one column,
Summary of Broadcasting Rule#
If a dimension in B is 1,
fmaccopies its values across that dimension.If A and B have different dimensions that are not 1,
fmacthrows an error.
Example for Matrix (using Bash)#
Create a Matrix (A), Dimension as 2 x 2 x 2#
!bart vec $(seq 1 8) array_A # Generate a array with values from 1 to 8
!bart reshape $(bart bitmask 0 1 2) 2 2 2 array_A matrix_A # Reshape the array to Dimension as 2 x 2 x 2
!bart show matrix_A
+1.000000e+00+0.000000e+00i +2.000000e+00+0.000000e+00i
+3.000000e+00+0.000000e+00i +4.000000e+00+0.000000e+00i
+5.000000e+00+0.000000e+00i +6.000000e+00+0.000000e+00i
+7.000000e+00+0.000000e+00i +8.000000e+00+0.000000e+00i
Create a Matrix (B), Dimension as 2 x 2 x 2#
!bart vec $(seq 2 9) array_B # Generate a array with values from 2 to 9
!bart reshape $(bart bitmask 0 1 2) 2 2 2 array_B matrix_B # Reshape the array to Dimension as 2 x 2 x 2
!bart show matrix_B
+2.000000e+00+0.000000e+00i +3.000000e+00+0.000000e+00i
+4.000000e+00+0.000000e+00i +5.000000e+00+0.000000e+00i
+6.000000e+00+0.000000e+00i +7.000000e+00+0.000000e+00i
+8.000000e+00+0.000000e+00i +9.000000e+00+0.000000e+00i
Example 1.1:#
Performs element-wise multiplication of matrix_A and matrix_B and stores the result in matrix_output
!bart fmac matrix_A matrix_B matrix_output
!bart show matrix_output
+2.000000e+00+0.000000e+00i +6.000000e+00+0.000000e+00i
+1.200000e+01+0.000000e+00i +2.000000e+01+0.000000e+00i
+3.000000e+01+0.000000e+00i +4.200000e+01+0.000000e+00i
+5.600000e+01+0.000000e+00i +7.200000e+01+0.000000e+00i
-A: Adds the computed result to an existing output file instead of overwriting it#
Mathematical Representation#
Without -A:
With -A:
where the previous values in \(O_{\text{existing}}\) are updated by adding the new computation.
Example 1.2:#
Performs element-wise multiplication of matrix_A and matrix_B, and then adds the result to matrix_output for Example 1.1 instead of overwriting it.
!bart fmac -A matrix_A matrix_B matrix_output
!bart show matrix_output
+4.000000e+00+0.000000e+00i +1.200000e+01+0.000000e+00i
+2.400000e+01+0.000000e+00i +4.000000e+01+0.000000e+00i
+6.000000e+01+0.000000e+00i +8.400000e+01+0.000000e+00i
+1.120000e+02+0.000000e+00i +1.440000e+02+0.000000e+00i
-C: Takes the complex conjugate of the second input (input2) before performing the element-wise multiplication.#
Given two matrices:
The element-wise multiplication produces:
Using -C for Complex Conjugation#
When using the -C option, the second input matrix B is conjugated before multiplication:
where the complex conjugate of \(B\) is:
Example 1.3:#
Performs element-wise multiplication of matrix_A with the complex conjugate of matrix_C, and stores the result in matrix_output_conjugate.
!bart vec 1+1i 2+2i matrix_C # Generate a matrix with Dimension as 2 x 1
!bart show matrix_C
+1.000000e+00+1.000000e+00i +2.000000e+00+2.000000e+00i
!bart fmac -C matrix_A matrix_C matrix_output_conjugate
!bart show matrix_output_conjugate
+1.000000e+00-1.000000e+00i +4.000000e+00-4.000000e+00i
+3.000000e+00-3.000000e+00i +8.000000e+00-8.000000e+00i
+5.000000e+00-5.000000e+00i +1.200000e+01-1.200000e+01i
+7.000000e+00-7.000000e+00i +1.600000e+01-1.600000e+01i
!bart show -m matrix_output_conjugate
Type: complex float
Dimensions: 16
AoD: 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
Note: As the example showing, if the dimensions of matrix_A and matrix_C do not match, and matrix_C with Singleton dimension. BART will repeat the elements of matrix_C along the mismatched dimension to match matrix_A. As shown in the example, the matrix_C (2×1) is repeated to perform element-wise multiplication with matrix_A.
-s b: Squashes dimensions (summed along the dimensions) specified by the bitmask b after performing element-wise multiplication.#
Example 1.4:#
Performs element-wise multiplication and sums over the first dimension.
!bart fmac -s 1 matrix_A matrix_B matrix_output_squash1
!bart show matrix_output
+4.000000e+00+0.000000e+00i +1.200000e+01+0.000000e+00i
+2.400000e+01+0.000000e+00i +4.000000e+01+0.000000e+00i
+6.000000e+01+0.000000e+00i +8.400000e+01+0.000000e+00i
+1.120000e+02+0.000000e+00i +1.440000e+02+0.000000e+00i
!bart show matrix_output_squash1
+8.000000e+00+0.000000e+00i +3.200000e+01+0.000000e+00i
+7.200000e+01+0.000000e+00i +1.280000e+02+0.000000e+00i
Example 1.5:#
Performs element-wise multiplication and sums over the all the dimensions.
!bart fmac -s 7 matrix_A matrix_B matrix_output_squash2
!bart show matrix_output_squash2
+2.400000e+02+0.000000e+00i
Example Workflow for MRI (python)#
# Importing the required libraries
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import cfl
from bart import bart
1. Generate Phantom in k-Space Directly#
Generate Shepp-Logan phantom directly in k-space:
ksp = bart(1, 'phantom -x 128 -k -s 8')
# Visualizing the images using Matplotlib
plt.figure(figsize=(16,20))
for i in range(8):
plt.subplot(1, 8, i+1)
plt.imshow(abs(ksp[...,i])**.3, cmap='gray')
plt.title('kspace image {}'.format(i))
2. Generate Sensitivity Maps#
Create sensitivity maps for 8 coils:
-m 1: Compute one set of sensitivity maps.
sens = bart(1, 'ecalib -m 1', ksp)
Done.
sens.shape
(128, 128, 1, 8)
# Visualizing the sensitivity maps using Matplotlib
plt.figure(figsize=(16,20))
for i in range(8):
plt.subplot(1, 8, i+1)
plt.imshow(abs(sens[...,i]), cmap='gray')
plt.title('sens {}'.format(i))
3. Generate a Brain Image by phantom#
brain = bart(1, 'phantom --BRAIN -x 128')
# Visualizing the image using Matplotlib
plt.figure(figsize=(4, 6))
plt.imshow(np.abs(brain), cmap='gray')
plt.title('Ksapce Image')
Text(0.5, 1.0, 'Ksapce Image')
Example 2.1: Use bart fmac to apply sensitivity maps to the brain image:#
brain_fmac = bart(1, 'fmac', brain, sens)
# Visualizing the images using Matplotlib
plt.figure(figsize=(16,20))
for i in range(8):
plt.subplot(1, 8, i+1)
plt.imshow(abs(brain_fmac[...,i]), cmap='gray')
plt.title('Brain Image {}'.format(i))
Performing an inverse FFT on k-space data (ksp)
phantom = bart(1, 'fft -i 3', ksp)
# Visualizing the images using Matplotlib
plt.figure(figsize=(16,20))
for i in range(8):
plt.subplot(1, 8, i+1)
plt.imshow(abs(phantom[...,i]), cmap='gray')
plt.title('Phantom Image {}'.format(i))
Example 2.2: Performing coil combination using sensitivity maps (sens) to obtain a final image.#
-C: Uses the conjugate of sens.
-s 8: Squashes dimension 8 (typically the coil dimension in BART).
image = bart(1, 'fmac -C -s 8', phantom, sens)
# Visualizing the image using Matplotlib
plt.figure(figsize=(4, 6))
plt.imshow(np.abs(image), cmap='gray')
plt.title('Image')
Text(0.5, 1.0, 'Image')