IR_block.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. # -*- coding: utf-8 -*-
  2. """
  3. A subroutine to add IR block.
  4. Requires the params structure as input.
  5. @author: petrm
  6. """
  7. import os
  8. import sys
  9. # need to add the project dir with the utilities folder to path:
  10. project_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
  11. sys.path.append(project_dir)
  12. from pypulseq.make_sinc_pulse import make_sinc_pulse
  13. from pypulseq.make_trapezoid import make_trapezoid
  14. from pypulseq.make_delay import make_delay
  15. from pypulseq.calc_duration import calc_duration as calc_dur
  16. from math import pi
  17. import numpy as np
  18. def IR_block(params, hw, IR_geom_offset):
  19. # function creates inversion recovery block with delay
  20. # =============================================================================
  21. # Get params from GUI
  22. # =============================================================================
  23. t_inv = params['t_inv']
  24. t_BW_product_inv = params['t_BW_product_inv']
  25. TI_calc_block = params['TI_calc_block']
  26. if not 'dG' in params:
  27. params['dG'] = hw.grad_ramp_time
  28. spoiler_area = params['magn_prep_spoiler_area']
  29. if not 'flip_IR' in params:
  30. params['flip_IR'] = round(180 * pi / 180, 3)
  31. # =============================================================================
  32. # We agreed that IR in 3D is always nonselective. FoV_ss is a 3D indicator
  33. # =============================================================================
  34. if 'FoV_ss' in params:
  35. slice_selective = False
  36. else:
  37. slice_selective = True
  38. # =============================================================================
  39. # Calculate module
  40. # =============================================================================
  41. rf_IR_output = make_sinc_pulse(flip_angle = params['flip_IR'],
  42. system = hw,
  43. duration = t_inv,
  44. slice_thickness = params['inv_thkn'],
  45. apodization = 0.5,
  46. time_bw_product = round(t_BW_product_inv, 8),
  47. freq_offset = 0,
  48. phase_offset = 90 * pi / 180,
  49. return_gz = slice_selective)
  50. if slice_selective: # in this case, rf_IR_output is a list of namespaces
  51. rf_IR = rf_IR_output[0]
  52. gz_IR = rf_IR_output[1]
  53. rf_IR.freq_offset = IR_geom_offset * gz_IR.amplitude # calculate IR freq offset from the geom offset (for slices)
  54. duration_IR_object = calc_dur(gz_IR)
  55. IR_return_objects_list = [rf_IR, gz_IR]
  56. else: # in this case, rf_IR_output is actually rf_IR itself
  57. rf_IR = rf_IR_output
  58. duration_IR_object = calc_dur(rf_IR)
  59. IR_return_objects_list = [rf_IR]
  60. # calculate spoiler
  61. gz_IR_spoil = make_trapezoid(channel = "z",
  62. system = hw,
  63. area = spoiler_area,
  64. rise_time = params['dG'])
  65. duration_gz_IR_spoil = calc_dur(gz_IR_spoil)
  66. # calculate delay
  67. TI_delay = TI_calc_block - 1/2*duration_IR_object - duration_gz_IR_spoil
  68. TI_delay = np.ceil(TI_delay / hw.grad_raster_time) * hw.grad_raster_time
  69. delay_IR = make_delay(TI_delay)
  70. # calculate duration
  71. duration_IR_total = duration_IR_object + duration_gz_IR_spoil + TI_delay
  72. return (IR_return_objects_list, [gz_IR_spoil], [delay_IR]), duration_IR_total