def test_transmission_sampling(self): def compute_transmission_function(n, ps, energy, material): wedge = np.tile(np.arange(n), [n, 1]) * ps wedge = StaticBody(wedge, ps, material=material) return wedge.transfer((n, n), ps, energy, exponent=True) def compute_distance(n, ps, lam, ps_per_lam): ca = (lam / (ps_per_lam * ps)).simplified.magnitude alpha = np.arccos(ca) theta = np.pi / 2 - alpha return (n * ps / (2 * np.tan(theta))).simplified n = 32 ps = 1 * q.um energies = np.arange(5, 30) * q.keV energy = 10 * q.keV lam = physics.energy_to_wavelength(energy) # Delta causes phase shift between two adjacent pixels by 2 Pi delta = (lam / ps).simplified.magnitude ri = np.ones_like(energies.magnitude, dtype=np.complex) * delta + 0j material = Material('dummy', ri, energies) # Single object u = compute_transmission_function(n, ps, energy, material) self.assertFalse(physics.is_wavefield_sampling_ok(u)) # 4x supersampling => phase shift Pi/2 u = compute_transmission_function(4 * n, ps / 4, energy, material) self.assertTrue(physics.is_wavefield_sampling_ok(u)) # 4x supersampling with 2 objects => phase shift Pi n *= 4 ps /= 4 wedge = np.tile(np.arange(n), [n, 1]) * ps wedge = StaticBody(wedge, ps, material=material) u = physics.transfer_many([wedge, wedge], (n, n), ps, energy, exponent=True) self.assertFalse(physics.is_wavefield_sampling_ok(u)) # X-ray source with a parabolic phase profile n = 128 ps = 1 * q.um trajectory = Trajectory([(n / 2, n / 2, 0)] * ps) # 1 pixel per wavelength => insufficient sampling d = compute_distance(n, ps, lam, 1) source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, d, 1, np.array([0.2, 0.8]) * q.mm, ps, trajectory, phase_profile='parabola') u = source.transfer((n, n), ps, energy, exponent=True) self.assertFalse(physics.is_wavefield_sampling_ok(u)) # 4 pixel per wavelength => good sampling d = compute_distance(n, ps, lam, 4) source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, d, 1, np.array([0.2, 0.8]) * q.mm, ps, trajectory, phase_profile='parabola') u = source.transfer((n, n), ps, energy, exponent=True) self.assertTrue(physics.is_wavefield_sampling_ok(u))
def setUp(self): # Double precision needed for spherical phase profile syris.init(double_precision=True, device_index=0) self.dE = 0.1 * q.keV self.energies = np.arange(14.8, 15, self.dE.magnitude) * q.keV self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.ps = 10 * q.um self.source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory)
def test_bending_magnet_approx(self): source_2 = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, profile_approx=False) for e in self.energies: u_0 = self.source.transfer((16, 16), self.ps, e, t=0 * q.s).get().real u_1 = source_2.transfer((16, 16), self.ps, e, t=0 * q.s).get().real perc = u_0 / u_1 # Allow 0.1 % difference np.testing.assert_allclose(perc, 1, rtol=1e-3)
def test_transfer(self): shape = 10 # No trajectory self.source.transfer(shape, self.ps, self.energies[0], t=0 * q.s) # Width may be larger self.source.transfer((shape, 2 * shape), self.ps, self.energies[0], t=0 * q.s) # With trajectory n = 16 x = z = np.zeros(n) y = np.linspace(0, 1, n) * q.mm tr = Trajectory(zip(x, y, z) * q.mm, pixel_size=10 * q.um, furthest_point=0*q.m, velocity=1 * q.mm / q.s) source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, trajectory=tr) im_0 = source.transfer(shape, self.ps, self.energies[0], t=0 * q.s).get() im_1 = source.transfer(shape, self.ps, self.energies[0], t=tr.time / 2).get() # There must be a difference between two different times and given trajectory self.assertGreater(np.abs(im_1 - im_0).max(), 0) # Test exponent u = source.transfer(shape, self.ps, self.energies[0], exponent=False).get() u_exp = source.transfer(shape, self.ps, self.energies[0], exponent=True).get() np.testing.assert_almost_equal(u, np.exp(u_exp))
def main(): syris.init() n = 512 shape = (n, n) ps = 1 * q.um dE = 1 * q.keV energies = np.arange(5, 30, dE.magnitude) * q.keV cp = make_triangle(n=16) * 1e-1 tr = Trajectory(cp, velocity=10 * q.um / q.s, pixel_size=ps) bm = BendingMagnet(2.5 * q.GeV, 100 * q.mA, 1.5 * q.T, 30 * q.m, dE, (200, 800) * q.um, ps, tr) # Flat at time = 0 flat_0 = (abs(bm.transfer((512, 256), ps, energies[0], t=0 * q.s)) ** 2).real.get() # Flat at half the time flat_1 = (abs(bm.transfer((512, 256), ps, energies[0], t=tr.time / 2)) ** 2).real.get() plt.subplot(121) plt.imshow(flat_0) f = plt.subplot(122) plt.imshow(flat_1) plt.show()
class TestSources(SyrisTest): def setUp(self): # Double precision needed for spherical phase profile default_syris_init(double_precision=True) self.dE = 0.1 * q.keV self.energies = np.arange(14.8, 15, self.dE.magnitude) * q.keV self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.ps = 10 * q.um self.source = BendingMagnet( 2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, ) def test_bending_magnet_approx(self): source_2 = BendingMagnet( 2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, profile_approx=False, ) for e in self.energies: u_0 = self.source.transfer((16, 16), self.ps, e, t=0 * q.s).get().real u_1 = source_2.transfer((16, 16), self.ps, e, t=0 * q.s).get().real perc = u_0 / u_1 # Allow 0.1 % difference np.testing.assert_allclose(perc, 1, rtol=1e-3) def test_transfer(self): shape = 10 # No trajectory self.source.transfer(shape, self.ps, self.energies[0], t=0 * q.s) # Width may be larger self.source.transfer((shape, 2 * shape), self.ps, self.energies[0], t=0 * q.s) # With trajectory n = 16 x = z = np.zeros(n) y = np.linspace(0, 1, n) * q.mm tr = Trajectory( list(zip(x, y, z)) * q.mm, pixel_size=10 * q.um, furthest_point=0 * q.m, velocity=1 * q.mm / q.s, ) source = BendingMagnet( 2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, trajectory=tr, ) im_0 = source.transfer(shape, self.ps, self.energies[0], t=0 * q.s).get() im_1 = source.transfer(shape, self.ps, self.energies[0], t=tr.time / 2).get() # There must be a difference between two different times and given trajectory self.assertGreater(np.abs(im_1 - im_0).max(), 0) # Test exponent u = source.transfer(shape, self.ps, self.energies[0], exponent=False).get() u_exp = source.transfer(shape, self.ps, self.energies[0], exponent=True).get() np.testing.assert_almost_equal(u, np.exp(u_exp)) def test_set_phase_profile(self): with self.assertRaises(XRaySourceError): self.source.phase_profile = "foo" self.source.phase_profile = "plane" self.source.phase_profile = "parabola" self.source.phase_profile = "sphere" def test_phase_profile(self): n = 64 shape = (n, n) ps = 1 * q.um energy = 10 * q.keV offset = (n // 2, n // 2) * ps def test_one_phase_profile(phase_profile): self.source.phase_profile = phase_profile phase = np.angle( self.source.transfer(shape, ps, energy, offset=offset).get()) gt = np.angle( make_phase(n, ps, self.source.sample_distance, energy, phase_profile=phase_profile)) np.testing.assert_almost_equal(phase, gt) # Plane wave self.source.phase_profile = "plane" u = self.source.transfer(shape, ps, energy).get() np.testing.assert_almost_equal(np.angle(u), 0) test_one_phase_profile("parabola") test_one_phase_profile("sphere") def test_wiggler(self): wiggler = Wiggler( 2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, 4, ) energy = 10 * q.keV w_flux = wiggler.get_flux(energy, 0 * q.mrad, self.ps) flux = self.source.get_flux(energy, 0 * q.mrad, self.ps) self.assertAlmostEqual((w_flux / flux).magnitude, 4) shape = (128, 128) w_u = np.abs(wiggler.transfer(shape, self.ps, energy).get())**2 u = np.abs(self.source.transfer(shape, self.ps, energy).get())**2 np.testing.assert_almost_equal(w_u / u, 4)
class TestSources(SyrisTest): def setUp(self): # Double precision needed for spherical phase profile syris.init(double_precision=True, device_index=0) self.dE = 0.1 * q.keV self.energies = np.arange(14.8, 15, self.dE.magnitude) * q.keV self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.ps = 10 * q.um self.source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory) @opencl @slow def test_bending_magnet_approx(self): source_2 = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, profile_approx=False) for e in self.energies: u_0 = self.source.transfer((16, 16), self.ps, e, t=0 * q.s).get().real u_1 = source_2.transfer((16, 16), self.ps, e, t=0 * q.s).get().real perc = u_0 / u_1 # Allow 0.1 % difference np.testing.assert_allclose(perc, 1, rtol=1e-3) @opencl def test_transfer(self): shape = 10 # No trajectory self.source.transfer(shape, self.ps, self.energies[0], t=0 * q.s) # Width may be larger self.source.transfer((shape, 2 * shape), self.ps, self.energies[0], t=0 * q.s) # With trajectory n = 16 x = z = np.zeros(n) y = np.linspace(0, 1, n) * q.mm tr = Trajectory(zip(x, y, z) * q.mm, pixel_size=10 * q.um, furthest_point=0*q.m, velocity=1 * q.mm / q.s) source = BendingMagnet(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, trajectory=tr) im_0 = source.transfer(shape, self.ps, self.energies[0], t=0 * q.s).get() im_1 = source.transfer(shape, self.ps, self.energies[0], t=tr.time / 2).get() # There must be a difference between two different times and given trajectory self.assertGreater(np.abs(im_1 - im_0).max(), 0) # Test exponent u = source.transfer(shape, self.ps, self.energies[0], exponent=False).get() u_exp = source.transfer(shape, self.ps, self.energies[0], exponent=True).get() np.testing.assert_almost_equal(u, np.exp(u_exp)) def test_set_phase_profile(self): with self.assertRaises(XRaySourceError): self.source.phase_profile = 'foo' self.source.phase_profile = 'plane' self.source.phase_profile = 'parabola' self.source.phase_profile = 'sphere' @opencl def test_phase_profile(self): n = 64 shape = (n, n) ps = 1 * q.um energy = 10 * q.keV offset = (n / 2, n / 2) * ps def test_one_phase_profile(phase_profile): self.source.phase_profile = phase_profile phase = np.angle(self.source.transfer(shape, ps, energy, offset=offset).get()) gt = np.angle(make_phase(n, ps, self.source.sample_distance, energy, phase_profile=phase_profile)) np.testing.assert_almost_equal(phase, gt) # Plane wave self.source.phase_profile = 'plane' u = self.source.transfer(shape, ps, energy).get() np.testing.assert_almost_equal(np.angle(u), 0) test_one_phase_profile('parabola') test_one_phase_profile('sphere') @opencl def test_wiggler(self): wiggler = Wiggler(2.5 * q.GeV, 150 * q.mA, 1.5 * q.T, 30 * q.m, self.dE, np.array([0.2, 0.8]) * q.mm, self.ps, self.trajectory, 4) energy = 10 * q.keV w_flux = wiggler.get_flux(energy, 0 * q.mrad, self.ps) flux = self.source.get_flux(energy, 0 * q.mrad, self.ps) self.assertAlmostEqual((w_flux / flux).magnitude, 4) shape = (128, 128) w_u = np.abs(wiggler.transfer(shape, self.ps, energy).get()) ** 2 u = np.abs(self.source.transfer(shape, self.ps, energy).get()) ** 2 np.testing.assert_almost_equal(w_u / u, 4)