Exemplo n.º 1
0
def propagate(samples, shape, energies, distance, pixel_size, region=None,
              apply_phase_factor=False, mollified=True, detector=None, offset=None,
              queue=None, out=None, t=None, check=True, block=False):
    """Propagate *samples* with *shape* as (y, x) which are
    :class:`syris.opticalelements.OpticalElement` instances at *energies* to *distance*. Use
    *pixel_size*, limit coherence to *region*, *apply_phase_factor* is as by the Fresnel
    approximation phase factor, *offset* is the sample offset. *queue* an OpenCL command queue,
    *out* a PyOpenCL Array. If *block* is True, wait for the kernels to finish. If *check* is True,
    check the transmission function sampling.
    """
    if queue is None:
        queue = cfg.OPENCL.queue
    u = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_cplx)
    intensity = cl_array.zeros(queue, shape, cfg.PRECISION.np_float)

    for energy in energies:
        u.fill(0)
        u = transfer_many(samples, shape, pixel_size, energy, offset=offset,
                            queue=queue, out=u, t=t, check=check, block=block)
        if distance != 0 * q.m:
            lam = energy_to_wavelength(energy)
            propagator = compute_propagator(u.shape[0], distance, lam, pixel_size, region=region,
                                            apply_phase_factor=apply_phase_factor,
                                            mollified=mollified, queue=queue, block=block)
            fft_2(u, queue=queue, block=block)
            u *= propagator
            ifft_2(u, queue=queue, block=block)
        if detector:
            intensity += detector.convert(abs(u) ** 2, energy)
        else:
            intensity += abs(u) ** 2

    return intensity
    def test_fft(self):
        data = gpu_util.get_array(np.random.normal(100, 100,
                                                   size=(4, 4)).astype(cfg.PRECISION.np_float))
        orig = gpu_util.get_host(data)
        data = ip.fft_2(data)
        ip.ifft_2(data)
        np.testing.assert_almost_equal(orig, data.get().real, decimal=4)

        # With a plan
        from pyfft.cl import Plan
        plan = Plan((4, 4), queue=cfg.OPENCL.queue)
        data = ip.fft_2(np.copy(orig), plan=plan)
        ip.ifft_2(data, plan=plan)
        np.testing.assert_almost_equal(orig, data.get().real, decimal=4)

        # Test double precision
        syris.init(double_precision=True, device_index=0)
        data = gpu_util.get_array(np.random.normal(100, 100,
                                                   size=(4, 4)).astype(cfg.PRECISION.np_float))
        gt = np.fft.fft2(data.get())
        data = ip.fft_2(data)
        np.testing.assert_almost_equal(gt, data.get(), decimal=4)

        gt = np.fft.ifft2(data.get())
        data = ip.ifft_2(data)
        np.testing.assert_almost_equal(gt, data.get(), decimal=4)
Exemplo n.º 3
0
def propagate_numerically(n, w, ps, d, lam):
    """Propagate square aperture numerically."""
    LOG.info('Numerical propagation with n: {}, ps: {}'.format(n, ps))
    u_0 = np.zeros((n, n), dtype=cfg.PRECISION.np_cplx)
    wp = int(np.round(w / ps).simplified.magnitude)
    region = slice(n / 2 - wp, n / 2 + wp, 1)
    u_0[region, region] = 1 + 0j

    fp = compute_propagator(n, d, lam, ps, mollified=False)
    u_0 = fft_2(u_0)
    u_0 *= fp
    ifft_2(u_0)
    res = abs(u_0) ** 2

    return crop_to_aperture(res, w, ps)
Exemplo n.º 4
0
    def test_fft(self):
        data = gpu_util.get_array(
            np.random.normal(100, 100, size=(4, 4)).astype(cfg.PRECISION.np_float)
        )
        orig = gpu_util.get_host(data)
        data = ip.fft_2(data)
        ip.ifft_2(data)
        np.testing.assert_almost_equal(orig, data.get().real, decimal=4)

        # Test double precision
        default_syris_init(double_precision=True)
        data = gpu_util.get_array(
            np.random.normal(100, 100, size=(4, 4)).astype(cfg.PRECISION.np_float)
        )
        gt = np.fft.fft2(data.get())
        data = ip.fft_2(data)
        np.testing.assert_almost_equal(gt, data.get(), decimal=4)

        gt = np.fft.ifft2(data.get())
        data = ip.ifft_2(data)
        np.testing.assert_almost_equal(gt, data.get(), decimal=4)
Exemplo n.º 5
0
def main():
    args = parse_args()
    syris.init()
    # Propagate to 20 cm
    d = 5 * q.cm
    # Compute grid
    n_camera = 256
    n = n_camera * args.supersampling
    shape = (n, n)
    material = get_material("pmma_5_30_kev.mat")
    energy = 15 * q.keV
    ps = 1 * q.um
    ps_hd = ps / args.supersampling
    radius = n / 4.0 * ps_hd

    fmt = "                     Wavelength: {}"
    print(fmt.format(energy_to_wavelength(energy)))
    fmt = "Pixel size used for propagation: {}"
    print(fmt.format(ps_hd.rescale(q.um)))
    print("                  Field of view: {}".format(n *
                                                       ps_hd.rescale(q.um)))
    fmt = "                Sphere diameter: {}"
    print(fmt.format(2 * radius))

    sample = make_sphere(n, radius, pixel_size=ps_hd, material=material)
    projection = sample.project((n, n), ps_hd).get() * 1e6
    projection = decimate(projection, (n_camera, n_camera), average=True).get()
    # Propagation with a monochromatic plane incident wave
    hd = propagate([sample], shape, [energy], d, ps_hd).get()
    ld = decimate(hd, (n_camera, n_camera), average=True).get()

    kernel = compute_tie_kernel(n_camera, ps, d, material, energy)
    mju = material.get_attenuation_coefficient(energy).rescale(1 /
                                                               q.m).magnitude
    f_ld = fft_2(ld)
    f_ld *= get_array(kernel.astype(cfg.PRECISION.np_float))
    retrieved = ifft_2(f_ld).get().real
    retrieved = -1 / mju * np.log(retrieved) * 1e6

    if args.output_thickness:
        imageio.imwrite(args.output_thickness, projection)
    if args.output_projection:
        imageio.imwrite(args.output_projection, ld)
    if args.output_retrieved:
        imageio.imwrite(args.output_retrieved, retrieved)

    show(hd, title="High resolution")
    show(ld, title="Low resolution (detector)")
    show(retrieved, title="Retrieved [um]")
    show(projection, title="Projection [um]")
    show(projection - retrieved, title="Projection - retrieved")
    plt.show()
Exemplo n.º 6
0
    def make_sequence(
        self,
        t_start,
        t_end,
        shape=None,
        shot_noise=True,
        amplifier_noise=True,
        source_blur=True,
        queue=None,
    ):
        """Make images between times *t_start* and *t_end*."""
        if queue is None:
            queue = cfg.OPENCL.queue
        shape_0 = self.detector.camera.shape
        if shape is None:
            shape = shape_0
        ps_0 = self.detector.pixel_size
        ps = shape_0[0] / float(shape[0]) * ps_0
        fps = self.detector.camera.fps
        frame_time = 1 / fps
        times = (np.arange(
            t_start.simplified.magnitude,
            t_end.simplified.magnitude,
            frame_time.simplified.magnitude,
        ) * q.s)
        image = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_float)
        source_blur_kernel = None
        if source_blur:
            source_blur_kernel = self.make_source_blur(shape,
                                                       ps,
                                                       queue=queue,
                                                       block=False)

        fmt = "Making sequence with shape {} and pixel size {} from {} to {}"
        LOG.debug(fmt.format(shape, ps, t_start, t_end))

        for t_0 in times:
            image.fill(0)
            t = t_0
            t_next = self.get_next_time(t, ps)
            while t_next < t_0 + frame_time:
                LOG.debug("Motion blur: {} -> {}".format(t, t_next))
                image += self.compute_intensity(t, t_next, shape, ps)
                t = t_next
                t_next = self.get_next_time(t, ps)
            image += self.compute_intensity(t, t_0 + frame_time, shape, ps)
            if source_blur:
                image = ip.ifft_2(ip.fft_2(image) * source_blur_kernel).real
            camera_image = self.detector.camera.get_image(
                image, shot_noise=shot_noise, amplifier_noise=amplifier_noise)
            LOG.debug("Image: {} -> {}".format(t_0, t_0 + frame_time))
            yield camera_image
Exemplo n.º 7
0
def propagate(samples, shape, energies, distance, pixel_size, region=None,
              apply_phase_factor=False, mollified=True, detector=None, offset=None,
              queue=None, out=None, t=None, check=True, block=False):
    """Propagate *samples* with *shape* as (y, x) which are
    :class:`syris.opticalelements.OpticalElement` instances at *energies* to *distance*. Use
    *pixel_size*, limit coherence to *region*, *apply_phase_factor* is as by the Fresnel
    approximation phase factor, *offset* is the sample offset. *queue* an OpenCL command queue,
    *out* a PyOpenCL Array. If *block* is True, wait for the kernels to finish. If *check* is True,
    check the transmission function sampling.
    """
    if queue is None:
        queue = cfg.OPENCL.queue
    u = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_cplx)
    intensity = cl_array.zeros(queue, shape, cfg.PRECISION.np_float)

    for energy in energies:
        u.fill(0)
        u = transfer_many(samples, shape, pixel_size, energy, offset=offset,
                            queue=queue, out=u, t=t, check=check, block=block)
        if distance != 0 * q.m:
            lam = energy_to_wavelength(energy)
            propagator = compute_propagator(u.shape[0], distance, lam, pixel_size, region=region,
                                            apply_phase_factor=apply_phase_factor,
                                            mollified=mollified, queue=queue, block=block)
            fft_2(u, queue=queue, block=block)
            for sample in samples:
                try:
                    u *= sample.transfer_fourier(shape, pixel_size, energy, t=t, queue=queue,
                                                 out=None, block=block)
                except NotImplementedError:
                    LOG.debug('%s does not support fourier space transfer', sample)
            u *= propagator
            ifft_2(u, queue=queue, block=block)
        if detector:
            intensity += detector.convert(abs(u) ** 2, energy)
        else:
            intensity += abs(u) ** 2

    return intensity
Exemplo n.º 8
0
    def apply_blur(self,
                   intensity,
                   distance,
                   pixel_size,
                   queue=None,
                   block=False):
        """Apply source blur based on van Cittert-Zernike theorem at *distance*."""
        fwhm = (distance * self.size / self.sample_distance).simplified
        sigma = smath.fwnm_to_sigma(fwhm, n=2)
        psf = ip.get_gauss_2d(intensity.shape,
                              sigma,
                              pixel_size=pixel_size,
                              fourier=True,
                              queue=queue,
                              block=block)

        return ip.ifft_2(ip.fft_2(intensity) * psf).real
Exemplo n.º 9
0
    def make_sequence(self, t_start, t_end, shape=None, shot_noise=True, amplifier_noise=True,
                      source_blur=True, queue=None):
        """Make images between times *t_start* and *t_end*."""
        if queue is None:
            queue = cfg.OPENCL.queue
        shape_0 = self.detector.camera.shape
        if shape is None:
            shape = shape_0
        ps_0 = self.detector.pixel_size
        ps = shape_0[0] / float(shape[0]) * ps_0
        fps = self.detector.camera.fps
        frame_time = 1 / fps
        times = np.arange(t_start.simplified.magnitude, t_end.simplified.magnitude,
                          frame_time.simplified.magnitude) * q.s
        image = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_float)
        source_blur_kernel = None
        if source_blur:
            source_blur_kernel = self.make_source_blur(shape, ps, queue=queue, block=False)

        fmt = 'Making sequence with shape {} and pixel size {} from {} to {}'
        LOG.debug(fmt.format(shape, ps, t_start, t_end))

        for t_0 in times:
            image.fill(0)
            t = t_0
            t_next = self.get_next_time(t, ps)
            while t_next < t_0 + frame_time:
                LOG.debug('Motion blur: {} -> {}'.format(t, t_next))
                image += self.compute_intensity(t, t_next, shape, ps)
                t = t_next
                t_next = self.get_next_time(t, ps)
            image += self.compute_intensity(t, t_0 + frame_time, shape, ps)
            if source_blur:
                image = ip.ifft_2(ip.fft_2(image) * source_blur_kernel).real
            camera_image = self.detector.camera.get_image(image, shot_noise=shot_noise,
                                                          amplifier_noise=amplifier_noise)
            LOG.debug('Image: {} -> {}'.format(t_0, t_0 + frame_time))
            yield camera_image
Exemplo n.º 10
0
    def compute_intensity(self,
                          t_0,
                          t_1,
                          shape,
                          pixel_size,
                          queue=None,
                          block=False,
                          flat=False):
        """Compute intensity between times *t_0* and *t_1*."""

        exp_time = (t_1 - t_0).simplified.magnitude

        if queue is None:
            queue = cfg.OPENCL.queue
        u = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_cplx)
        u_sample = cl_array.zeros(queue, shape, cfg.PRECISION.np_cplx)
        intensity = cl_array.zeros(queue, shape, cfg.PRECISION.np_float)

        for energy in self.energies:
            u.fill(1)
            for oeid, oe in enumerate(self.oe):

                if flat and oe == self.sample:
                    continue

                u *= oe.transfer(shape,
                                 pixel_size,
                                 energy,
                                 t=t_0,
                                 queue=queue,
                                 out=u_sample,
                                 check=False,
                                 block=block)

                # Propagate and blur optical element when not source
                if self.distances[oeid] != 0 * q.m and oe != self.source:
                    lam = energy_to_wavelength(energy)
                    propagator = compute_propagator(u.shape[0],
                                                    self.distances[oeid],
                                                    lam,
                                                    pixel_size,
                                                    queue=queue,
                                                    block=block,
                                                    mollified=True)

                    ip.fft_2(u, queue=queue, block=block)

                    sdistance = np.sum(self.distances[:oeid + 1])
                    fwhm = (self.distances[oeid] * self.source.size /
                            sdistance).simplified
                    sigma = smath.fwnm_to_sigma(fwhm, n=2)
                    psf = ip.get_gauss_2d(shape,
                                          sigma,
                                          pixel_size=pixel_size,
                                          fourier=True,
                                          queue=queue,
                                          block=block)
                    u *= psf
                    u *= propagator
                    ip.ifft_2(u, queue=queue, block=block)

            intensity += self.detector.convert(abs(u)**2, energy)

        return intensity * exp_time