def make_se_epi(self): kwargs_for_opts = {"max_grad": self.max_grad, "grad_unit": "mT/m", "max_slew": self.max_slew, "slew_unit": "T/m/s", "rf_dead_time": 10e-6, "adc_dead_time": 10e-6} system = Opts(kwargs_for_opts) seq = Sequence(system) slice_thickness = 3e-3 flip = 90 * pi / 180 kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 3e-3, "slice_thickness": slice_thickness, "apodization": 0.5, "time_bw_product": 4} rf, gz = makesincpulse(kwargs_for_sinc, 2) # plt.plot(rf.t[0], rf.signal[0]) # plt.show() delta_k = 1 / self.fov k_width = self.Nx * delta_k readout_time = 3.2e-4 kwargs_for_gx = {"channel": 'x', "system": system, "flat_area": k_width, "flat_time": readout_time} gx = maketrapezoid(kwargs_for_gx) kwargs_for_adc = {"num_samples": self.Nx, "system": system, "duration": gx.flat_time, "delay": gx.rise_time} adc = makeadc(kwargs_for_adc) pre_time = 8e-4 kwargs_for_gxpre = {"channel": 'x', "system": system, "area": -gx.area / 2, "duration": pre_time} gx_pre = maketrapezoid(kwargs_for_gxpre) kwargs_for_gz_reph = {"channel": 'z', "system": system, "area": -gz.area / 2, "duration": pre_time} gz_reph = maketrapezoid(kwargs_for_gz_reph) kwargs_for_gy_pre = {"channel": 'y', "system": system, "area": -self.Ny / 2 * delta_k, "duration": pre_time} gy_pre = maketrapezoid(kwargs_for_gy_pre) dur = ceil(2 * sqrt(delta_k / system.max_slew) / 10e-6) * 10e-6 kwargs_for_gy = {"channel": 'y', "system": system, "area": delta_k, "duration": dur} gy = maketrapezoid(kwargs_for_gy) flip = 180 * pi / 180 kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 500e-6} rf180 = makeblockpulse(kwargs_for_sinc) kwargs_for_gz_spoil = {"channel": 'z', "system": system, "area": gz.area * 2, "duration": 3 * pre_time} gz_spoil = maketrapezoid(kwargs_for_gz_spoil) TE = self.te duration_to_center = (self.Nx / 2 + 0.5) * calcduration(gx) + self.Ny / 2 * calcduration(gy) delayTE1 = TE / 2 - calcduration(gz) / 2 - pre_time - calcduration(gz_spoil) - calcduration(rf180) / 2 delayTE2 = TE / 2 - calcduration(rf180) / 2 - calcduration(gz_spoil) - duration_to_center delay1 = makedelay(delayTE1) delay2 = makedelay(delayTE2) seq.add_block(rf, gz) seq.add_block(gx_pre, gy_pre, gz_reph) seq.add_block(delay1) seq.add_block(gz_spoil) seq.add_block(rf180) seq.add_block(gz_spoil) seq.add_block(delay2) for i in range(self.Ny): seq.add_block(gx, adc) seq.add_block(gy) gx.amplitude = -gx.amplitude seq.add_block(makedelay(1)) return seq
"time_bw_product": 4 } rf, gz = makesincpulse(kwargs_for_sinc, 2) # plt.plot(rf.t[0], rf.signal[0]) # plt.show() delta_k = 1 / fov kWidth = Nx * delta_k readoutTime = Nx * dt_GE kwargs_for_gx = { "channel": 'x', "system": system, "flat_area": kWidth, "flat_time": readoutTime } gx = maketrapezoid(kwargs_for_gx) kwargs_for_adc = { "num_samples": Nx, "system": system, "duration": gx.flat_time, "delay": gx.rise_time } adc = makeadc(kwargs_for_adc) pre_time = 8e-4 kwargs_for_gxpre = { "channel": 'x', "system": system, "area": -gx.area / 2 - delta_k / 2, "duration": pre_time }
Ny = 256 slice_thickness = 3e-3 dt_GE = 4e-6 flip = 90 * pi / 180 kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 2.5e-3, "slice_thickness": slice_thickness, "apodization": 0.5, "time_bw_product": 4} rf, gz = makesincpulse(kwargs_for_sinc, 2) # plt.plot(rf.t[0], rf.signal[0]) # plt.show() delta_k = 1 / fov kWidth = Nx * delta_k readoutTime = Nx * dt_GE kwargs_for_gx = {"channel": 'x', "system": system, "flat_area": kWidth, "flat_time": readoutTime} gx = maketrapezoid(kwargs_for_gx) kwargs_for_adc = {"num_samples": Nx, "system": system, "duration": gx.flat_time, "delay": gx.rise_time} adc = makeadc(kwargs_for_adc) kwargs_for_gxpre = {"channel": 'x', "system": system, "area": -gx.area / 2, "duration": 2.5e-3} gx_pre = maketrapezoid(kwargs_for_gxpre) kwargs_for_gz_reph = {"channel": 'z', "system": system, "area": -gz.area / 2, "duration": 2.5e-3} gz_reph = maketrapezoid(kwargs_for_gz_reph) flip = 180 * pi / 180 kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 2.5e-3, "slice_thickness": slice_thickness, "apodization": 0.5, "time_bw_product": 4} rf180, gz180 = makesincpulse(kwargs_for_sinc, 2) delayTE1 = TE / 2 - calcduration(gz_reph) - calcduration(rf) - calcduration(rf180) / 2
def makeblockpulse(kwargs, nargout=1): """ Makes a Holder object for an RF pulse Event. Parameters ---------- kwargs : dict Key value mappings of RF Event parameters_params and values. nargout: int Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater than 1 will return the Gz Event along with the RF Event. Returns ------- Tuple consisting of: rf : Holder RF Event configured based on supplied kwargs. gz : Holder Slice select trapezoidal gradient Event. """ flip_angle = kwargs.get("flip_angle") system = kwargs.get("system", Opts()) duration = kwargs.get("duration", 0) freq_offset = kwargs.get("freq_offset", 0) phase_offset = kwargs.get("phase_offset", 0) time_bw_product = kwargs.get("time_bw_product", 4) bandwidth = kwargs.get("bandwidth", 0) max_grad = kwargs.get("max_grad", 0) max_slew = kwargs.get("max_slew", 0) slice_thickness = kwargs.get("slice_thickness", 0) if duration == 0: if time_bw_product > 0: duration = time_bw_product / bandwidth elif bandwidth > 0: duration = 1 / (4 * bandwidth) else: raise ValueError('Either bandwidth or duration must be defined') BW = 1 / (4 * duration) N = round(duration / 1e-6) t = [x * system.rf_raster_time for x in range(N)] signal = flip_angle / (2 * np.pi) / duration * np.ones(len(t)) rf = Holder() rf.type = 'rf' rf.signal = signal rf.t = t rf.freq_offset = freq_offset rf.phase_offset = phase_offset rf.dead_time = system.rf_dead_time fill_time = 0 if nargout > 1: if slice_thickness < 0: raise ValueError('Slice thickness must be provided') if max_grad > 0: system.max_grad = max_grad if max_slew > 0: system.max_slew = max_slew amplitude = BW / slice_thickness area = amplitude * duration kwargs_for_trap = {'channel': 'z', 'system': system, 'flat_time': duration, 'flat_area': area} gz = maketrapezoid(kwargs_for_trap) fill_time = gz.rise_time t_fill = np.array([x * 1e-6 for x in range(int(round(fill_time / 1e-6)))]) rf.t = np.array([t_fill, rf.t + t_fill[-1], t_fill + rf.t[-1] + t_fill[-1]]) rf.signal = np.array([np.zeros(t_fill.size), rf.signal, np.zeros(t_fill.size)]) if fill_time < rf.dead_time: fill_time = rf.dead_time - fill_time t_fill = np.array([x * 1e-6 for x in range(int(round(fill_time / 1e-6)))]) rf.t = np.insert(rf.t, 0, t_fill) + t_fill[-1] rf.t = np.reshape(rf.t, (1, len(rf.t))) rf.signal = np.insert(rf.signal, 0, np.zeros(t_fill.size)) rf.signal = np.reshape(rf.signal, (1, len(rf.signal))) if nargout > 1: return rf, gz else: return rf
def makearbitraryrf(kwargs, nargout=1): """ Makes a Holder object for an arbitrary RF pulse Event. Parameters ---------- kwargs : dict Key value mappings of RF Event parameters_params and values. nargout: int Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater than 1 will return the Gz Event along with the RF Event. Returns ------- rf : Holder RF Event configured based on supplied kwargs. gz : Holder Slice select trapezoidal gradient Event. """ flip_angle = kwargs.get("flip_angle") system = kwargs.get("system", Opts()) signal = kwargs.get("signal", 0) freq_offset = kwargs.get("freq_offset", 0) phase_offset = kwargs.get("phase_offset", 0) time_bw_product = kwargs.get("time_bw_product", 0) bandwidth = kwargs.get("bandwidth", 0) max_grad = kwargs.get("max_grad", 0) max_slew = kwargs.get("max_slew", 0) slice_thickness = kwargs.get("slice_thickness", 0) signal = signal / sum( signal * system.rf_raster_time) * flip_angle / (2 * pi) N = len(signal) duration = N * system.rf_raster_time t = [x * system.rfRasterTime for x in range(0, N)] rf = Holder() rf.type = 'rf' rf.signal = signal rf.t = t rf.freq_offset = freq_offset rf.phase_offset = phase_offset rf.rf_dead_time = system.rf_dead_time if nargout > 1: if slice_thickness <= 0: raise ValueError('Slice thickness must be provided') if bandwidth <= 0: raise ValueError('Bandwdith of pulse must be provided') system.maxgrad = max_grad if max_grad > 0 else system.maxgrad system.max_slew = max_slew if max_slew > 0 else system.max_slew BW = bandwidth if time_bw_product > 0: BW = time_bw_product / duration amplitude = BW / slice_thickness area = amplitude * duration kwargs_for_trap = { "channel": 'z', "system": system, "flat_time": duration, "flat_area": area } gz = maketrapezoid(**kwargs_for_trap) t_fill = [x * 1e-6 for x in range(1, round(gz.riseTime / 1e-6))] rf.t = [t_fill, rf.t + t_fill[-1], t_fill + rf.t[-1] + t_fill[-1]] rf.signal = [np.zeros(len(t_fill)), rf.signal, np.zeros(len(t_fill))] return rf, gz
def makesincpulse(kwargs, nargout=1): """ Makes a Holder object for an RF pulse Event. Parameters ---------- kwargs : dict Key value mappings of RF Event parameters_params and values. nargout: int Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater than 1 will return the Gz Event along with the RF Event. Returns ------- Tuple consisting of: rf : Holder RF Event configured based on supplied kwargs. gz : Holder Slice select trapezoidal gradient Event. """ flip_angle = kwargs.get("flip_angle") system = kwargs.get("system", Opts()) duration = kwargs.get("duration", 0) freq_offset = kwargs.get("freq_offset", 0) phase_offset = kwargs.get("phase_offset", 0) time_bw_product = kwargs.get("time_bw_product", 4) apodization = kwargs.get("apodization", 0) max_grad = kwargs.get("max_grad", 0) max_slew = kwargs.get("max_slew", 0) slice_thickness = kwargs.get("slice_thickness", 0) BW = time_bw_product / duration alpha = apodization N = int(round(duration / 1e-6)) t = np.zeros((1, N)) for x in range(1, N + 1): t[0][x - 1] = x * system.rf_raster_time tt = t - (duration / 2) window = np.zeros((1, tt.shape[1])) for x in range(0, tt.shape[1]): window[0][x] = 1.0 - alpha + alpha * np.cos( 2 * np.pi * tt[0][x] / duration) signal = np.multiply(window, np.sinc(BW * tt)) flip = np.sum(signal) * system.rf_raster_time * 2 * np.pi signal = signal * flip_angle / flip rf = Holder() rf.type = 'rf' rf.signal = signal rf.t = t rf.freq_offset = freq_offset rf.phase_offset = phase_offset rf.dead_time = system.rf_dead_time fill_time = 0 if nargout > 1: if slice_thickness == 0: raise ValueError('Slice thickness must be provided') system.max_grad = max_grad if max_grad > 0 else system.max_grad system.max_slew = max_slew if max_slew > 0 else system.max_slew amplitude = BW / slice_thickness area = amplitude * duration kwargs_for_trap = { "channel": 'z', "system": system, "flat_time": duration, "flat_area": area } gz = maketrapezoid(kwargs_for_trap) fill_time = gz.rise_time nfill_time = int(round(fill_time / 1e-6)) t_fill = np.zeros((1, nfill_time)) for x in range(1, nfill_time + 1): t_fill[0][x - 1] = x * 1e-6 temp = np.concatenate((t_fill[0], rf.t[0] + t_fill[0][-1])) temp = temp.reshape((1, len(temp))) rf.t = np.resize(rf.t, temp.shape) rf.t[0] = temp z = np.zeros((1, t_fill.shape[1])) temp2 = np.concatenate((z[0], rf.signal[0])) temp2 = temp2.reshape((1, len(temp2))) rf.signal = np.resize(rf.signal, temp2.shape) rf.signal[0] = temp2 if fill_time < rf.dead_time: fill_time = rf.dead_time - fill_time t_fill = np.array( [x * 1e-6 for x in range(int(round(fill_time / 1e-6)))]) rf.t = np.insert(rf.t, 0, t_fill) + t_fill[-1] rf.t = np.reshape(rf.t, (1, len(rf.t))) rf.signal = np.insert(rf.signal, 0, (np.zeros(t_fill.size))) rf.signal = np.reshape(rf.signal, (1, len(rf.signal))) # Following 2 lines of code are workarounds for numpy returning 3.14... for np.angle(-0.00...) negative_zero_indices = np.where(rf.signal == -0.0) rf.signal[negative_zero_indices] = 0 if nargout > 1: return rf, gz else: return rf
def make_event_holders(self): """Make appropriate Holder objects depending on the Event type.""" self.system = self.in_dict['system'] # arbgrad_file_path is only for arbitrary gradients arbgrad_file_path = self.all_event_def[ 'file_path'] if 'file_path' in self.all_event_def else None self.all_event_holders = {} for event in self.all_event_def: event_unique_name = event['event_unique_name'] event_name = event['event_name'] event_values = list(event['event_values'].values()) include_in_loop = event['include_in_loop'] if event_name == 'Delay': params = self.parse_config_params(event_values) delay = makedelay(params[0]) self.all_event_holders[ event_unique_name] = delay, include_in_loop elif event_name == 'SincRF': include_gz = event['include_gz'] max_grad, max_slew, flip_angle, duration, freq_offset, phase_offset, time_bw_product, apodization, slice_thickness = self.parse_config_params( event_values) flip_angle = math.radians(flip_angle) max_grad = convert.convert_from_to(max_grad, 'mT/m') max_slew = convert.convert_from_to(max_slew, 'mT/m/ms') max_grad = self.system.max_grad if max_grad == 0 else max_grad max_slew = self.system.max_slew if max_slew == 0 else max_slew kwargs_for_sinc = { "flip_angle": flip_angle, "system": self.system, "duration": duration, "freq_offset": freq_offset, "phase_offset": phase_offset, "time_bw_product": time_bw_product, "apodization": apodization, "max_grad": max_grad, "max_slew": max_slew, "slice_thickness": slice_thickness } if include_gz: rf, gz = makesincpulse(kwargs_for_sinc, 2) self.all_event_holders[ event_unique_name] = rf, include_in_loop self.all_event_holders[ 'gz_' + event_unique_name] = gz, include_in_loop else: rf = makesincpulse(kwargs_for_sinc) self.all_event_holders[ event_unique_name] = rf, include_in_loop elif event_name == 'BlockRF': include_gz = event['include_gz'] max_grad, max_slew, flip_angle, duration, freq_offset, phase_offset, time_bw_product, bandwidth, slice_thickness = self.parse_config_params( event_values) flip_angle = math.radians(flip_angle) max_grad = convert.convert_from_to(max_grad, 'mT/m') max_slew = convert.convert_from_to(max_slew, 'mT/m/ms') max_grad = self.system.max_grad if max_grad == 0 else max_grad max_slew = self.system.max_slew if max_slew == 0 else max_slew kwargs_for_block = { "flip_angle": flip_angle, "system": self.system, "duration": duration, "freq_offset": freq_offset, "phase_offset": phase_offset, "time_bw_product": time_bw_product, "bandwidth": bandwidth, "max_grad": max_grad, "max_slew": max_slew, "slice_thickness": slice_thickness } if include_gz: rf, gz = makeblockpulse(kwargs_for_block, 2) self.all_event_holders[ event_unique_name] = rf, include_in_loop self.all_event_holders[ 'gz_' + event_unique_name] = gz, include_in_loop else: rf = makeblockpulse(kwargs_for_block) self.all_event_holders[ event_unique_name] = rf, include_in_loop elif event_name == 'G': channel = event_values.pop(0) max_grad, max_slew, duration, area, flat_time, flat_area, amplitude, rise_time = self.parse_config_params( event_values) # area, flat_area and amplitude should be reset to -1 if user does not input any values. This is # because the default values are -1 in maketrap method. area = area if area != 0 else -1 flat_area = flat_area if flat_area != 0 else -1 amplitude = amplitude if amplitude != 0 else -1 max_grad = convert.convert_from_to(max_grad, 'mT/m') max_slew = convert.convert_from_to(max_slew, 'mT/m/ms') max_grad = self.system.max_grad if max_grad == 0 else max_grad max_slew = self.system.max_slew if max_slew == 0 else max_slew kwargs_for_trap = { "channel": channel, "system": self.system, "duration": duration, "area": area, "flat_time": flat_time, "flat_area": flat_area, "amplitude": amplitude, "max_grad": max_grad, "max_slew": max_slew, "rise_time": rise_time } trap = maketrapezoid(kwargs_for_trap) self.all_event_holders[ event_unique_name] = trap, include_in_loop elif event_name == 'GyPre': duration, area = self.parse_config_params(event_values) Ny = self.system.Ny delta_k = 1 / self.system.fov gy_pre_list = [] for i in range(int(Ny)): kwargs_for_gy_pre = { "channel": 'y', "system": self.system, "area": (i - Ny / 2) * delta_k, "duration": duration } if area != 0: kwargs_for_gy_pre['area'] = area gy_pre = maketrapezoid(kwargs_for_gy_pre) gy_pre_list.append(gy_pre) self.all_event_holders[event_unique_name] = gy_pre_list, True elif event_name == 'ArbGrad': channel = event_values.pop(0) max_grad, max_slew = self.parse_config_params(event_values) file = h5py.File(gpi.TranslateFileURI(arbgrad_file_path), "r") self.dataset = str() def append_if_dataset(name, obj): if isinstance(obj, h5py.Dataset): self.dataset = name return True file.visititems(append_if_dataset) waveform = file[self.dataset].value kwargs_for_arb_grad = { "channel": channel, "waveform": waveform, "max_grad": max_grad, "max_slew": max_slew, "system": self.system } arb_grad = makearbitrarygrad(kwargs_for_arb_grad) self.all_event_holders[ event_unique_name] = arb_grad, include_in_loop elif event_name == 'ADC': num_samples, dwell, duration, delay, freq_offset, phase_offset = self.parse_config_params( event_values) kwargs_for_adc = { "num_samples": num_samples, "system": self.system, "dwell": dwell, "duration": duration, "delay": delay, "freq_offset": freq_offset, "phase_offset": phase_offset } adc = makeadc(kwargs_for_adc) self.all_event_holders[ event_unique_name] = adc, include_in_loop