116 lines
4.0 KiB
Python
116 lines
4.0 KiB
Python
|
import numpy as np
|
||
|
from numpy import linalg as LA
|
||
|
import sys
|
||
|
from mpi4py import MPI
|
||
|
comm = MPI.COMM_WORLD
|
||
|
size = comm.Get_size()
|
||
|
rank = comm.Get_rank()
|
||
|
|
||
|
# SENSE: Simulation of SENSitive Encoding algorithm proposed by K. Pruessmann, et. al. in:
|
||
|
# "SENSE: Sensitivity Enconding for Fast MRI" Mag. Res. in Medicine 42. (1999)
|
||
|
# written by Jeremias Garay (j.e.garay.labra@rug.nl)
|
||
|
|
||
|
def Sensitivity_Map(shape):
|
||
|
|
||
|
[Nx,Ny,Nz] = shape
|
||
|
[X,Y,Z] = np.meshgrid(np.linspace(0,Ny,Ny),np.linspace(0,Nx,Nx),np.linspace(0,Nz,Nz))
|
||
|
Xsense1 = (X/(Nx*2)-1)**2
|
||
|
Xsense2 = ((Nx-X)/(Nx*2)-1)**2
|
||
|
S_MAPS = [np.fft.fftshift(Xsense1),np.fft.fftshift(Xsense2)]
|
||
|
|
||
|
return S_MAPS
|
||
|
|
||
|
def SENSE_recon(S1,M1,S2,M2):
|
||
|
|
||
|
[Nx,Ny,Nz,Nt] = M1.shape
|
||
|
M = np.zeros([Nx,int(2*Ny),Nz,Nt],dtype=complex)
|
||
|
sm1 = np.fft.fftshift(S1)[:,:,0]
|
||
|
sm2 = np.fft.fftshift(S2)[:,:,0]
|
||
|
|
||
|
for j in range(Ny):
|
||
|
for k in range(Nx):
|
||
|
l1 = M1[k,j,:,:]; a1 = sm1[k,j]; a2 = sm1[k,j+Ny]
|
||
|
l2 = M2[k,j,:,:]; b1 = sm2[k,j]; b2 = sm2[k,j+Ny]
|
||
|
B = (l1*b1 - l2*a1)/(a2*b1 - b2*a1)
|
||
|
A = (l1*b2 - l2*a2)/(a1*b2 - a2*b1)
|
||
|
M[k,j,:,:] = A
|
||
|
M[k,j+Ny,:,:] = B
|
||
|
|
||
|
|
||
|
return M
|
||
|
|
||
|
def SENSE_recon2(S1,M1,S2,M2):
|
||
|
# With matrices as in the original paper!
|
||
|
|
||
|
[Nx,Ny,Nz,Nt] = M1.shape
|
||
|
M = np.zeros([Nx,int(2*Ny),Nz,Nt],dtype=complex)
|
||
|
sm1 = np.fft.fftshift(S1)[:,:,0]
|
||
|
sm2 = np.fft.fftshift(S2)[:,:,0]
|
||
|
sigma2 = 0.049**2
|
||
|
sigma2 = 1
|
||
|
Psi = np.diagflat(np.array([sigma2,sigma2])) # Error matrix Psi
|
||
|
Psi_inv = np.linalg.inv(Psi)
|
||
|
|
||
|
for j in range(Ny):
|
||
|
for k in range(Nx):
|
||
|
l1 = M1[k,j,:,:]; a1 = sm1[k,j]; a2 = sm1[k,j+Ny]
|
||
|
l2 = M2[k,j,:,:]; b1 = sm2[k,j]; b2 = sm2[k,j+Ny]
|
||
|
S = np.array([[a1,a2],[b1,b2]])
|
||
|
U = np.linalg.inv((np.transpose(S)*Psi_inv*S))*np.transpose(S)*Psi_inv
|
||
|
a = np.array([l1,l2])
|
||
|
a_resized = np.resize(a,(2,Nz*Nt))
|
||
|
v_resized = np.dot(U,a_resized)
|
||
|
v = np.resize(v_resized,(2,Nz,Nt))
|
||
|
M[k,j,:,:] = v[0,:,:]
|
||
|
M[k,j+Ny,:,:] = v[1,:,:]
|
||
|
|
||
|
|
||
|
return M
|
||
|
|
||
|
def SENSE_METHOD(Seq,R):
|
||
|
'''
|
||
|
Args:
|
||
|
ITOT: a numpy matrix with the full sampled (3D or 4D) dynamical data
|
||
|
R: the acceleration factor
|
||
|
'''
|
||
|
|
||
|
[row,col,dep,numt2] = Seq.shape
|
||
|
Seq_red = {}
|
||
|
SenseMAP = {}
|
||
|
[SenseMAP[0],SenseMAP[1]] = Sensitivity_Map([row,col,dep])
|
||
|
|
||
|
col2 = int(np.ceil(col/2))
|
||
|
|
||
|
for rs in range(R):
|
||
|
Seq_red[rs] = np.zeros([row,col2,dep,numt2],dtype=complex)
|
||
|
for t in range(numt2):
|
||
|
Kdata_0 = np.fft.fftn(Seq[:,:,:,t])
|
||
|
Kdata_0 = Kdata_0*SenseMAP[rs]
|
||
|
Kdata_0 = Kdata_0[:,0::R,:]
|
||
|
Seq_red[rs][:,:,:,t] = np.fft.ifftn(Kdata_0)
|
||
|
|
||
|
Seq_recon = SENSE_recon2(SenseMAP[0],Seq_red[0],SenseMAP[1],Seq_red[1])
|
||
|
|
||
|
return Seq_recon
|
||
|
|
||
|
def undersampling(Mx,My,Mz,options):
|
||
|
|
||
|
R = options['SENSE']['R']
|
||
|
|
||
|
for r in R:
|
||
|
if rank==0:
|
||
|
print('Using Acceleration Factor R = ' + str(r))
|
||
|
print('applying into x component')
|
||
|
Mx_s = SENSE_METHOD(Mx,r)
|
||
|
if rank==0:
|
||
|
print('applying into y component')
|
||
|
My_s = SENSE_METHOD(My,r)
|
||
|
if rank==0:
|
||
|
print('applying into z component')
|
||
|
Mz_s = SENSE_METHOD(Mz,r)
|
||
|
|
||
|
return [Mx_s,My_s,Mz_s]
|
||
|
|
||
|
|
||
|
|