def quantitative_fm(Mxys, dfs, T1s, T2s, PDs, TR, alpha, phase_cyc, mask=None): '''Find field map given quantitative maps. ''' resps = {} orig_size = np.asarray(T1s).shape if mask is None: mask = np.ones(Mxys.shape) Mxys = np.asarray(Mxys).flatten() T1s = np.asarray(T1s).flatten() T2s = np.asarray(T2s).flatten() PDs = np.asarray(PDs).flatten() mask = np.asarray(mask).flatten() fm = np.zeros(Mxys.size) for ii in range(Mxys.size): if mask[ii]: # Cache results for later in case we come across the same T1,T2,PD if (PDs[ii], T1s[ii], T2s[ii]) not in resps: resps[(PDs[ii], T1s[ii], T2s[ii])] = get_df_responses(T1s[ii], T2s[ii], PDs[ii], TR, alpha, phase_cyc, dfs) # Find the appropriate off-resonance value for this T1,T2,PD,Mxy idx, val = find_nearest(resps[(PDs[ii], T1s[ii], T2s[ii])], Mxys[ii]) fm[ii] = dfs[idx] else: fm[ii] = 0 return (fm.reshape(orig_size))
def quantitative_fm(Mxys, dfs, T1s, T2s, PDs, TR, alpha, phase_cyc, mask=None): '''Find field map given quantitative maps. Parameters ========== Mxys : array_like Complex transverse signal we measure. dfs : array_like Off-resonance values to simulate over. T1s : array_like scalar T1 longitudinal recovery value in seconds. T2s : array_like scalar T2 transverse decay value in seconds. PDs : array_like scalar proton density value scaled the same as acquisiton. TR : float Repetition time in seconds. alpha : float Flip angle in radians. phase_cyc : float RF phase cycling in radians. mask : array_like Boolean mask to tell which pixels we should compute df for. Returns ======= fm : array_like Field map. ''' resps = {} orig_size = np.asarray(T1s).shape if mask is None: mask = np.ones(Mxys.shape) Mxys = np.asarray(Mxys).flatten() T1s = np.asarray(T1s).flatten() T2s = np.asarray(T2s).flatten() PDs = np.asarray(PDs).flatten() mask = np.asarray(mask).flatten() fm = np.zeros(Mxys.size) for ii in range(Mxys.size): if mask[ii]: # Cache results for later in case we come across the same T1,T2,PD if (PDs[ii], T1s[ii], T2s[ii]) not in resps: resps[(PDs[ii], T1s[ii], T2s[ii])] = get_df_responses(T1s[ii], T2s[ii], PDs[ii], TR, alpha, phase_cyc, dfs) # Find the appropriate off-resonance value for this T1,T2,PD,Mxy idx, _val = find_nearest(resps[(PDs[ii], T1s[ii], T2s[ii])], Mxys[ii]) fm[ii] = dfs[idx] else: fm[ii] = 0 return fm.reshape(orig_size)
def random_match_by_col(x, T, return_sorted=False): '''Given matrix T, choose reordering of x that matches it col by col. Parameters ========== x : array_like Array to find ordering of. T : array_like Target matrix. return_sorted : bool, optional Whether or not to return the sorted matrix. Returns ======= idx : array_like Flattened indices giving sorted order. array_like, optional Sorted array. ''' # Find number of basis functions, fi, and number of samples, M M, N = T.shape[:] # Keep a list of fij that we haven't done yet fijs = list(range(M)) # Find a good ordering for each basis function done = False xk = x.copy() f = np.zeros(T.shape, dtype=x.dtype) indices = np.arange(x.size).reshape(x.shape) with tqdm(desc='Matching', total=M, leave=False) as pbar: while not done: # Choose a row idx = np.random.choice(np.arange(len(fijs))) jj = fijs[idx] # Choose a column for ii in np.random.permutation(list(range(N))): ind, f[ii, jj] = find_nearest(xk, T[ii, jj]) indices[ii, jj] = ind xk[np.unravel_index(ind, x.shape)] = np.inf # Finalize the best fit, i.e., min || f[:, jj] - X[jj] || min_err = np.abs((f - T)**2).mean(axis=0).argsort().tolist() min_err = [me for me in min_err if me in fijs] fijs.remove(min_err[0]) # Check the stopping condition if not fijs: done = True pbar.update(1) # If we asked for the sorted matrix, send it back, too if return_sorted: return(indices.flatten(), f) return indices.flatten()
def quantitative_fm_scalar(Mxy, dfs, T1, T2, PD, TR, alpha, phase_cyc): '''For scalar T1,T2,PD''' # Simulate over the total range of off-resonance values resp = get_df_responses(T1, T2, PD, TR, alpha, phase_cyc, dfs) # Find the response that matches Mxy most closely idx, val = find_nearest(resp, Mxy) # Return the df's value, because that's really what the caller wanted return (dfs[idx])
def gen_sort1d(x, T): '''Given 1D transform T, sort 1d signal, x. Parameters ========== x : array_like 1D signal to find ordering of. T : array_like Transform matrix. Returns ======= array_like Flattened indices giving sorted order. ''' M, N = T.shape[:] assert x.size == N, 'T, x must be conformal!' # Get a list of all columns cols = list(range(N)) f = np.zeros(T.shape, dtype=x.dtype) indices = np.tile(np.arange(x.size)[:, None], (1, N)) # Order x to approximate a single column of T for col in cols: xk = x.copy() for row in range(M): ind, f[row, col] = find_nearest(xk, T[row, col]) indices[row, col] = ind xk[ind] = np.inf min_err = np.abs((f - T)**2).mean(axis=0).argsort() return indices[:, min_err[0]]
def quantitative_fm_scalar(Mxy, dfs, T1, T2, PD, TR, alpha, phase_cyc): '''For scalar T1, T2, PD. Parameters ========== Mxy : float Complex transverse signal we measure. dfs : array_like Off-resonance values to simulate over. T1 : float scalar T1 longitudinal recovery value in seconds. T2 : float scalar T2 transverse decay value in seconds. PD : float scalar proton density value scaled the same as acquisiton. TR : float Repetition time in seconds. alpha : float Flip angle in radians. phase_cyc : float RF phase cycling in radians. Returns ======= float Off-resonace value that most closely matches Mxy prior. ''' # Simulate over the total range of off-resonance values resp = get_df_responses(T1, T2, PD, TR, alpha, phase_cyc, dfs) # Find the response that matches Mxy most closely idx, _val = find_nearest(resp, Mxy) # Return the df's value, because that's really what the caller wanted return dfs[idx]