Beispiel #1
0
    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))
Beispiel #2
0
    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)
Beispiel #3
0
    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)
Beispiel #4
0
    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))
Beispiel #5
0
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()
Beispiel #6
0
    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))
Beispiel #7
0
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)
Beispiel #8
0
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)