def test_ideal(self): model = sycomore.como.Model( self.species, self.m0, [["half_echo", sycomore.TimeInterval(self.TR/2.)]]) magnetization = [] for i in range(self.TR_count): model.apply_pulse( sycomore.Pulse(self.flip_angle, (math.pi/3+(i%2)*math.pi)*rad)) model.apply_time_interval("half_echo") magnetization.append(model.isochromat()) model.apply_time_interval("half_echo") root = os.environ["SYCOMORE_TEST_DATA"] with open(os.path.join(root, "baseline", "GRE_ideal.dat"), "rb") as fd: contents = fd.read() baseline = struct.unpack((int(len(contents)/8))*"d", contents) self.assertEqual(len(baseline), 3*self.TR_count) for i in range(self.TR_count): m_test = magnetization[i] m_baseline = baseline[3*i:3*(i+1)] self.assertAlmostEqual(m_test[0], m_baseline[0]) self.assertAlmostEqual(m_test[1], m_baseline[1]) self.assertAlmostEqual(m_test[2], m_baseline[2])
def test_diffusion(self): model = sycomore.como.Model( sycomore.Species(0 * Hz, 0 * Hz, 1 * um * um / ms), sycomore.Magnetization(0, 0, 1), [["foo", sycomore.TimeInterval(500 * ms, 0.1 * rad / um)]]) model.apply_pulse(sycomore.Pulse(40 * deg, 0 * deg)) model.apply_time_interval("foo") grid = model.magnetization() for index, _ in sycomore.GridScanner(grid.origin(), grid.shape()): if index == sycomore.Index(-1): self.assertEqual(grid[index].p, 0) self.assertEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0 + 0.003062528150606j) elif index == sycomore.Index(0): self.assertEqual(grid[index].p, 0) self.assertAlmostEqual(grid[index].z, 0.766044443118978) self.assertEqual(grid[index].m, 0) elif index == sycomore.Index(1): self.assertAlmostEqual(grid[index].p, 0 - 0.003062528150606j) self.assertEqual(grid[index].z, 0) self.assertEqual(grid[index].m, 0) else: self.assertEqual(grid[index].p, 0) self.assertAlmostEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0)
def test_duration_constructor(self): interval = sycomore.TimeInterval(1 * ms) self.assertEqual(interval.duration, 1 * ms) self._test_quantity_array(interval.gradient_amplitude, 3 * [0. * T / m]) self._test_quantity_array(interval.gradient_area, 3 * [0. * T / m * s]) self._test_quantity_array(interval.gradient_dephasing, 3 * [0. * rad / m]) self._test_quantity_array(interval.gradient_moment, 3 * [0. * rad / m])
def test_comparison(self): interval_1 = sycomore.TimeInterval(1. * ms, 2 * T / m) interval_2 = sycomore.TimeInterval(1. * ms, 2 * T / m) interval_3 = sycomore.TimeInterval(1. * ms, [2 * T / m, 2 * T / m, 2 * T / m]) self.assertTrue(interval_1 == interval_2) self.assertTrue(interval_1 == interval_3) self.assertFalse(interval_1 != interval_2) self.assertFalse(interval_1 != interval_3) interval_4 = sycomore.TimeInterval(4. * ms, 2 * T / m) self.assertFalse(interval_1 == interval_4) self.assertTrue(interval_1 != interval_4) interval_5 = sycomore.TimeInterval(1. * ms, 4 * T / m) self.assertFalse(interval_1 == interval_5) self.assertTrue(interval_1 != interval_5)
def test_amplitude_scalar_constructor(self): interval = sycomore.TimeInterval(1. * ms, 2. * mT / dm) self.assertEqual(interval.duration, 1e-3 * s) self._test_quantity_array(interval.gradient_amplitude, 3 * [20 * mT / m]) self._test_quantity_array(interval.gradient_area, 3 * [20 * mT / m * ms]) self._test_quantity_array(interval.gradient_dephasing, 3 * [5350.4437993378515 * rad / m]) self._test_quantity_array(interval.gradient_moment, 3 * [5350.4437993378515 * rad / m])
def test_dephasing_scalar_constructor(self): interval = sycomore.TimeInterval(1. * ms, 2. * rad / dm) self.assertEqual(interval.duration, 1e-3 * s) self._test_quantity_array(interval.gradient_amplitude, 3 * [74.76015355016015 * uT / m]) self._test_quantity_array(interval.gradient_area, 3 * [74.76015355016015 * uT / m * ms]) self._test_quantity_array(interval.gradient_dephasing, 3 * [20. * rad / m]) self._test_quantity_array(interval.gradient_moment, 3 * [20. * rad / m])
def test_dephasing_vector_constructor(self): interval = sycomore.TimeInterval( 1. * ms, [2 * rad / dm, 4 * rad / m, 8 * rad / dam]) self.assertEqual(interval.duration, 1e-3 * s) self._test_quantity_array(interval.gradient_amplitude, [ 74.76015355016015 * uT / m, 14.95203071003203 * uT / m, 2.9904061420064063 * uT / m ]) self._test_quantity_array(interval.gradient_area, [ 74.76015355016015 * uT / m * ms, 14.95203071003203 * uT / m * ms, 2.9904061420064063 * uT / m * ms ]) self._test_quantity_array(interval.gradient_dephasing, [20 * rad / m, 4 * rad / m, 0.8 * rad / m]) self._test_quantity_array(interval.gradient_moment, [20 * rad / m, 4 * rad / m, 0.8 * rad / m])
def test_amplitude_vector_constructor(self): interval = sycomore.TimeInterval( 1. * ms, [2. * mT / dm, 4. * mT / m, 8. * mT / dam]) self.assertEqual(interval.duration, 1e-3 * s) self._test_quantity_array(interval.gradient_amplitude, [20. * mT / m, 4. * mT / m, 0.8 * mT / m]) self._test_quantity_array( interval.gradient_area, [20. * mT / m * ms, 4. * mT / m * ms, 0.8 * mT / m * ms]) self._test_quantity_array(interval.gradient_dephasing, [ 5350.4437993378515 * rad / m, 1070.0887598675702 * rad / m, 214.01775197351404 * rad / m ]) self._test_quantity_array(interval.gradient_moment, [ 5350.4437993378515 * rad / m, 1070.0887598675702 * rad / m, 214.01775197351404 * rad / m ])
def test_off_resonance(self): species = sycomore.Species(0 * Hz, 0 * Hz, 0 * um * um / ms) m0 = sycomore.Magnetization(0, 0, 1) pulse = sycomore.Pulse(90 * deg, math.pi * rad) pulse_duration = 1 * ms pulse_support_size = 101 zero_crossings = 2 # NOTE: in the absence of relaxation and diffusion, the TR is meaningless TR = 500 * ms slice_thickness = 1 * mm t0 = pulse_duration / (2 * zero_crossings) sinc_pulse = sycomore.HardPulseApproximation( pulse, sycomore.linspace(pulse_duration, pulse_support_size), sycomore.sinc_envelope(t0), 1 / t0, slice_thickness, "rf") refocalization = sycomore.TimeInterval( (TR - pulse_duration) / 2., -sinc_pulse.get_gradient_moment() / 2) model = sycomore.como.Model( species, m0, [["rf", sinc_pulse.get_time_interval()], ["refocalization", refocalization]]) model.apply_pulse(sinc_pulse) model.apply_time_interval("refocalization") frequencies = sycomore.linspace(60. * rad / ms, 201) magnetization = [ model.isochromat(set(), sycomore.Point(), f) for f in frequencies ] root = os.environ["SYCOMORE_TEST_DATA"] with open(os.path.join(root, "baseline", "off_resonance.dat"), "rb") as fd: contents = fd.read() baseline = struct.unpack((int(len(contents) / 8)) * "d", contents) self.assertEqual(len(baseline), 2 * len(magnetization)) for i in range(len(magnetization)): self.assertAlmostEqual(sycomore.transversal(magnetization[i]), baseline[2 * i]) self.assertAlmostEqual(magnetization[i][2], baseline[2 * i + 1])
def test_gradient_properties(self): amplitude = [20 * mT / m, 40 * mT / m, 80 * mT / m] area = [20 * mT / m * ms, 40 * mT / m * ms, 80 * mT / m * ms] dephasing = [ 5350.4437993378515 * rad / m, 10700.887598675701 * rad / m, 21401.775197351402 * rad / m ] moment = dephasing for property in ["amplitude", "area", "dephasing", "moment"]: interval = sycomore.TimeInterval(1. * ms) setattr(interval, "gradient_{}".format(property), locals()[property][0]) self._test_quantity_array(interval.gradient_amplitude, 3 * [amplitude[0]]) self._test_quantity_array(interval.gradient_area, 3 * [area[0]]) self._test_quantity_array(interval.gradient_dephasing, 3 * [dephasing[0]]) self._test_quantity_array(interval.gradient_moment, 3 * [moment[0]]) setattr(interval, "gradient_{}".format(property), locals()[property]) self._test_quantity_array(interval.gradient_amplitude, amplitude) self._test_quantity_array(interval.gradient_area, area) self._test_quantity_array(interval.gradient_dephasing, dephasing) self._test_quantity_array(interval.gradient_moment, moment) interval.set_gradient(locals()[property][1]) self._test_quantity_array(interval.gradient_amplitude, 3 * [amplitude[1]]) self._test_quantity_array(interval.gradient_area, 3 * [area[1]]) self._test_quantity_array(interval.gradient_dephasing, 3 * [dephasing[1]]) self._test_quantity_array(interval.gradient_moment, 3 * [moment[1]]) interval.set_gradient(locals()[property]) self._test_quantity_array(interval.gradient_amplitude, amplitude) self._test_quantity_array(interval.gradient_area, area) self._test_quantity_array(interval.gradient_dephasing, dephasing) self._test_quantity_array(interval.gradient_moment, moment)
def test_pulse(self): model = sycomore.como.Model( sycomore.Species(1 * s, 0.1 * s), sycomore.Magnetization(0, 0, 1), [["dummy", sycomore.TimeInterval(0 * s)]]) model.apply_pulse(sycomore.Pulse(41 * deg, 27 * deg)) grid = model.magnetization() for index, _ in sycomore.GridScanner(grid.origin(), grid.shape()): if index == sycomore.Index(0): self.assertAlmostEqual(grid[index].p, 0.210607912662250 - 0.413341301933443j) self.assertAlmostEqual(grid[index].z, 0.754709580222772) self.assertAlmostEqual(grid[index].m, 0.210607912662250 + 0.413341301933443j) else: self.assertEqual(grid[index].p, 0) self.assertAlmostEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0)
def test_real(self): t0 = self.pulse_duration/(2*self.zero_crossings) sinc_pulse = sycomore.HardPulseApproximation( sycomore.Pulse(self.flip_angle, 0*rad), sycomore.linspace(self.pulse_duration, self.pulse_support_size), sycomore.sinc_envelope(t0), 1/t0, self.slice_thickness, "rf") half_echo = sycomore.TimeInterval( (self.TR-self.pulse_duration)/2., -sinc_pulse.get_gradient_moment()/2) model = sycomore.como.Model( self.species, self.m0, [ ["rf", sinc_pulse.get_time_interval()], ["half_echo", half_echo]]) magnetization = [] for i in range(self.TR_count): sinc_pulse.set_phase((math.pi/3+(i%2)*math.pi)*rad) model.apply_pulse(sinc_pulse) model.apply_time_interval("half_echo") magnetization.append(model.isochromat()) model.apply_time_interval("half_echo") root = os.environ["SYCOMORE_TEST_DATA"] with open(os.path.join(root, "baseline", "GRE_real.dat"), "rb") as fd: contents = fd.read() baseline = struct.unpack((int(len(contents)/8))*"d", contents) self.assertEqual(len(baseline), 3*self.TR_count) for i in range(self.TR_count): m_test = magnetization[i] m_baseline = baseline[3*i:3*(i+1)] self.assertAlmostEqual(m_test[0], m_baseline[0]) self.assertAlmostEqual(m_test[1], m_baseline[1]) self.assertAlmostEqual(m_test[2], m_baseline[2])
def test_time_interval(self): model = sycomore.como.Model( sycomore.Species(math.log(2) * Hz, math.log(2) * Hz), sycomore.Magnetization(0, 0, 1), [["foo", sycomore.TimeInterval(1 * s)], ["bar", sycomore.TimeInterval(1 * s)]]) model.apply_pulse(sycomore.Pulse(45 * deg, 90 * deg)) model.apply_time_interval("foo") grid = model.magnetization() for index, _ in sycomore.GridScanner(grid.origin(), grid.shape()): if index == sycomore.Index(-1, 0): self.assertEqual(grid[index].p, 0) self.assertEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0.25) elif index == sycomore.Index(0, 0): self.assertEqual(grid[index].p, 0) self.assertEqual(grid[index].z, 0.5 * (1 + math.sqrt(2) / 2)) self.assertEqual(grid[index].m, 0) elif index == sycomore.Index(1, 0): self.assertAlmostEqual(grid[index].p, 0.25) self.assertEqual(grid[index].z, 0) self.assertEqual(grid[index].m, 0) else: self.assertEqual(grid[index].p, 0) self.assertAlmostEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0) model.apply_time_interval("bar") grid = model.magnetization() for index, _ in sycomore.GridScanner(grid.origin(), grid.shape()): if index == sycomore.Index(-1, -1): self.assertEqual(grid[index].p, 0) self.assertEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0.125) elif index == sycomore.Index(0, 0): self.assertEqual(grid[index].p, 0) self.assertEqual(grid[index].z, 0.5 + 0.25 * (1 + math.sqrt(2) / 2)) self.assertEqual(grid[index].m, 0) elif index == sycomore.Index(1, 1): self.assertAlmostEqual(grid[index].p, 0.125) self.assertEqual(grid[index].z, 0) self.assertEqual(grid[index].m, 0) else: self.assertEqual(grid[index].p, 0) self.assertAlmostEqual(grid[index].z, 0) self.assertAlmostEqual(grid[index].m, 0) isochromat = model.isochromat() self.assertAlmostEqual(isochromat[0], 0.125 * math.sqrt(2)) self.assertAlmostEqual(isochromat[1], 0) self.assertAlmostEqual(isochromat[2], 0.5 + 0.25 * (1 + math.sqrt(2) / 2)) isochromat = model.isochromat( {sycomore.Index(0, 0), sycomore.Index(-1, -1)}) self.assertAlmostEqual(isochromat[0], 0.125 * math.sqrt(2) / 2) self.assertAlmostEqual(isochromat[1], 0) self.assertAlmostEqual(isochromat[2], 0.5 + 0.25 * (1 + math.sqrt(2) / 2))
def test_pulse_profile(self): species = sycomore.Species(0*Hz, 0*Hz, 0*um*um/ms) m0 = sycomore.Magnetization(0, 0, 1) pulse = sycomore.Pulse(90*deg, math.pi*rad) pulse_duration = 1*ms pulse_support_size = 101 zero_crossings = 2 # NOTE: in the absence of relaxation and diffusion, the TR is meaningless TR = 500*ms; slice_thickness = 1*mm; sampling_support_size = 501 t0 = pulse_duration/(2*zero_crossings) sinc_pulse = sycomore.HardPulseApproximation( pulse, sycomore.linspace(pulse_duration, pulse_support_size), sycomore.sinc_envelope(t0), 1/t0, slice_thickness, "rf") refocalization = sycomore.TimeInterval( (TR-pulse_duration)/2., -sinc_pulse.get_gradient_moment()/2) sampling_locations = sycomore.linspace( sycomore.Point(0*m, 0*m, 2*slice_thickness), sampling_support_size) model = sycomore.como.Model( species, m0, [ ["rf", sinc_pulse.get_time_interval()], ["refocalization", refocalization]]) model.apply_pulse(sinc_pulse) before_refocalization = [ model.isochromat(set(), p) for p in sampling_locations] model.apply_time_interval("refocalization") after_refocalization = [ model.isochromat(set(), p) for p in sampling_locations] root = os.environ["SYCOMORE_TEST_DATA"] with open(os.path.join(root, "baseline", "pulse_profile.dat"), "rb") as fd: contents = fd.read() baseline = struct.unpack((int(len(contents)/8))*"d", contents) self.assertEqual(len(baseline), 2*3*len(sampling_locations)) for i in range(len(sampling_locations)): m_test = before_refocalization[i] m_baseline = baseline[3*i:3*(i+1)] self.assertAlmostEqual(m_test[0], m_baseline[0]) self.assertAlmostEqual(m_test[1], m_baseline[1]) self.assertAlmostEqual(m_test[2], m_baseline[2]) for i in range(len(sampling_locations)): m_test = after_refocalization[i] m_baseline = baseline[ 3*(i+len(sampling_locations)):3*(i+len(sampling_locations)+1)] self.assertAlmostEqual(m_test[0], m_baseline[0]) self.assertAlmostEqual(m_test[1], m_baseline[1]) self.assertAlmostEqual(m_test[2], m_baseline[2])