def test_simulated_phantom_2d(self): # Create the target field map dim = 64 min_df, max_df = -500, 500 fx = np.linspace(min_df, max_df, dim) fy = np.zeros(dim) field_map, _ = np.meshgrid(fx, fy) # field_map = 100*np.random.normal(0,1,(dim,dim)) # view(field_map) # Simulate phase-cycled bSSFP acquisitons # Seems to be better with higher flip angle! # For some reason worse with higher TR args = { 'TR': 5e-3, 'alpha': np.pi / 3, 'dims': (dim, dim), 'FOV': ((-1, 1), (-1, 1)), 'radius': .75, 'field_map': field_map } pc_vals = [0, np.pi / 2, np.pi, 3 * np.pi / 2] pcs = np.zeros((len(pc_vals), dim, dim), dtype='complex') for ii, pc in enumerate(pc_vals): pcs[ii, ...] = bssfp_2d_cylinder(**args, phase_cyc=pc) # view(pcs) # Estimate field map using GS to ESM gsfm = gs_field_map( *[x.squeeze() for x in np.split(pcs, len(pc_vals))], TR=args['TR'], gs_recon_opts={'second_pass': False}) # TODO: Interestingly, the second pass solution fails... Why is this? # Now do sims for GRE for a sanity check TE1 = args['TR'] / 2 TE2 = TE1 - args['TR'] / 2 PD, T1s, T2s = cylinder_2d(dims=args['dims'], FOV=args['FOV'], radius=args['radius']) m1 = gre_sim(T1s, T2s, TR=args['TR'], TE=TE1, alpha=args['alpha'], field_map=args['field_map'], dphi=0, M0=PD, tol=1e-4) m2 = gre_sim(T1s, T2s, TR=args['TR'], TE=TE2, alpha=args['alpha'], field_map=args['field_map'], dphi=0, M0=PD, tol=1e-4) grefm = dual_echo_gre(m1, m2, TE1, TE2) # Phase wrap the real field map so we prove equivalence up to phase # unwrapping... dTE = np.abs(TE1 - TE2) field_map_pw = np.mod(field_map - 1 / (2 * dTE), 1 / dTE) - 1 / (2 * dTE) # Make sure we're getting the same thing when wrapped idx = np.where(np.abs(grefm) > 0) self.assertTrue(np.allclose(grefm[idx], field_map_pw[idx])) idx = np.where(np.abs(gsfm) > 0) self.assertTrue(np.allclose(gsfm[idx], field_map_pw[idx])) # Just for fun, try phase unwrapping... mask = np.zeros(gsfm.shape).astype(bool) mask[idx] = True # scale between [-pi,pi], do unwrap, scale back up scale_fac = np.pi / np.max(np.abs(gsfm)) * np.sign(np.max(gsfm)) val = unwrap_phase(mask * gsfm * scale_fac) / scale_fac # For some reason the edges are off by about pi, so let's clip it... val = val[:, 19:-19] field_map_clipped = field_map[:, 19:-19] idx = np.where(np.abs(val) > 0) self.assertTrue(np.allclose(field_map_clipped[idx], val[idx]))
for jj, pc in enumerate(pc_vals): bssfp_acqs[jj, ..., ii] = bssfp_acq(T1s, T2s, PD, tv_field_map[..., ii], alpha=bssfp_alpha, TR=bssfp_TR, phase_cyc=pc) # view(bssfp_acqs[0,...],movie_axis=-1) # view(np.concatenate((gre_acqs,bssfp_acqs[0,...])),movie_axis=-1) # Now get field maps recon_fm = np.zeros(tv_field_map.shape) for ii in trange(time_pts, leave=False, desc='GSFM'): recon_fm[..., ii] = gs_field_map(*[ x.squeeze() for x in np.split(bssfp_acqs[..., ii], len(pc_vals)) ], TR=bssfp_TR) # recon_fm[0,0,:] = 1 # ref pixel # view(recon_fm,movie_axis=-1) # view(np.stack((recon_fm[31,16,:],tv_field_map[31,16,:]))) # Compare to just getting field map 4 times avg_field_map = np.zeros(tv_field_map.shape) for ii in trange(len(pc_vals), desc='AvgFM', leave=False): avg_field_map += np.random.normal(0, sigma, tv_field_map.shape) avg_field_map[idx, :] += hrf0 avg_field_map /= len(pc_vals) if plots: plt.plot(hrf0, label='HDR') plt.plot(recon_fm[31, 16, :], label='Recon FM')
'TR': 5e-3, 'alpha': np.pi / 3, 'dims': (dim, dim), 'FOV': ((-1, 1), (-1, 1)), 'radius': .75, 'field_map': field_map } pc_vals = [0, np.pi / 2, np.pi, 3 * np.pi / 2] pcs = np.zeros((len(pc_vals), dim, dim), dtype='complex') for ii, pc in enumerate(pc_vals): pcs[ii, ...] = bssfp_2d_cylinder(**args, phase_cyc=pc) view(pcs) # Estimate field map using GS to ESM gsfm = gs_field_map(*[x.squeeze() for x in np.split( pcs, len(pc_vals))], \ TR=args['TR'], gs_recon_opts={'second_pass': False}) # TODO: Interestingly, the second pass solution fails... Why is this? view(gsfm) # Now do sims for GRE for a sanity check TE1 = args['TR'] / 2 TE2 = TE1 - args['TR'] / 2 PD, T1s, T2s = cylinder_2d(dims=args['dims'], FOV=args['FOV'], radius=args['radius']) m1 = gre_sim(T1s, T2s, TR=args['TR'], TE=TE1, alpha=args['alpha'],