예제 #1
0
파일: physics.py 프로젝트: erickzhou/syris
def compute_propagator(size, distance, lam, pixel_size, fresnel=True, region=None,
                       apply_phase_factor=False, mollified=True, queue=None, block=False):
    """Create a propagator with (*size*, *size*) dimensions for propagation *distance*, wavelength
    *lam* and *pixel_size*. If *fresnel* is True, use the Fresnel approximation, if it is False, use
    the full propagator (don't approximate the square root). *region* is the diameter of the the
    wavefront area which is capable of interference. If *apply_phase_factor* is True, apply the
    phase factor defined by Fresnel approximation. If *mollified* is True the aliased frequencies
    are suppressed. If command *queue* is specified, execute the kernel on it. If *block* is True,
    wait for the kernel to finish.
    """
    if size % 2:
        raise ValueError('Only even sizes are supported')
    if queue is None:
        queue = cfg.OPENCL.queue

    # Check the sampling
    r_cutoff = compute_aliasing_limit(size, lam, pixel_size, distance, fov=region, fourier=False)
    min_n = 4
    if r_cutoff < min_n:
        LOG.error('Propagator too narrow, propagation distance too small or pixel size too large')
    f_cutoff = compute_aliasing_limit(size, lam, pixel_size, distance, fov=region, fourier=True)
    if f_cutoff < min_n:
        LOG.error('Propagator too wide, propagation distance too large or pixel size too small')

    out = cl_array.Array(queue, (size, size), cfg.PRECISION.np_cplx)
    if apply_phase_factor:
        phase_factor = np.exp(2 * np.pi * distance.simplified / lam.simplified * 1j)
    else:
        phase_factor = 0 + 0j

    ev = cfg.OPENCL.programs['physics'].propagator(queue,
                                                   (size / 2 + 1, size / 2 + 1),
                                                   None,
                                                   out.data,
                                                   cfg.PRECISION.np_float(distance.simplified),
                                                   cfg.PRECISION.np_float(lam.simplified),
                                                   cfg.PRECISION.np_float(pixel_size.simplified),
                                                   g_util.make_vcomplex(phase_factor),
                                                   np.int32(fresnel))
    if block:
        ev.wait()

    if mollified:
        fwtm = compute_aliasing_limit(size, lam, pixel_size, distance,
                                      fov=size * pixel_size, fourier=True)
        if region is not None:
            fwtm_region = compute_aliasing_limit(size, lam, pixel_size, distance, region,
                                                 fourier=True)
            fwtm = min(fwtm_region, fwtm)

        sigma = fwnm_to_sigma(fwtm, n=10)
        mollifier = get_gauss_2d(size, sigma, fourier=False, queue=queue, block=block)
        out = out * mollifier

    return out
예제 #2
0
    def make_source_blur(self, shape, pixel_size, queue=None, block=False):
        """Make geometrical source blurring kernel with *shape* (y, x) size and *pixel_size*. Use
        OpenCL command *queue* and *block* if True.
        """
        l = self.source.sample_distance
        size = self.source.size
        width = (self.propagation_distance * size[1] / l).simplified.magnitude
        height = (self.propagation_distance * size[0] / l).simplified.magnitude
        sigma = (smath.fwnm_to_sigma(height, n=2), smath.fwnm_to_sigma(width, n=2)) * q.m

        return ip.get_gauss_2d(shape, sigma, pixel_size=pixel_size, fourier=True,
                               queue=queue, block=block)
 def _test_gauss(self, shape, fourier):
     """Test if the gauss in Fourier space calculated on a GPU is
     the same as Fourier transform of a gauss in real space.
     """
     sigma = (shape[0] * self.pixel_size.magnitude,
              shape[1] / 2 * self.pixel_size.magnitude) * self.pixel_size.units
     if fourier:
         # Make the profile broad
         sigma = (1. / sigma[0].magnitude, 1. / sigma[1].magnitude) * sigma.units
     gauss = ip.get_gauss_2d(shape, sigma, self.pixel_size, fourier=fourier).get()
     gt = get_gauss_2d(shape, sigma, self.pixel_size, fourier=fourier)
     np.testing.assert_almost_equal(gauss, gt)
예제 #4
0
파일: sources.py 프로젝트: erickzhou/syris
    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
예제 #5
0
    def make_source_blur(self, shape, pixel_size, queue=None, block=False):
        """Make geometrical source blurring kernel with *shape* (y, x) size and *pixel_size*. Use
        OpenCL command *queue* and *block* if True.
        """
        l = self.source.sample_distance
        size = self.source.size
        width = (self.propagation_distance * size[1] / l).simplified.magnitude
        height = (self.propagation_distance * size[0] / l).simplified.magnitude
        sigma = (smath.fwnm_to_sigma(
            height, n=2), smath.fwnm_to_sigma(width, n=2)) * q.m

        return ip.get_gauss_2d(shape,
                               sigma,
                               pixel_size=pixel_size,
                               fourier=True,
                               queue=queue,
                               block=block)
예제 #6
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
예제 #7
0
파일: physics.py 프로젝트: ufo-kit/syris
def compute_propagator(size, distance, lam, pixel_size, fresnel=True, region=None,
                       apply_phase_factor=False, mollified=True, queue=None, block=False):
    """Create a propagator with (*size*, *size*) dimensions for propagation *distance*, wavelength
    *lam* and *pixel_size*. If *fresnel* is True, use the Fresnel approximation, if it is False, use
    the full propagator (don't approximate the square root). *region* is the diameter of the the
    wavefront area which is capable of interference. If *apply_phase_factor* is True, apply the
    phase factor defined by Fresnel approximation. If *mollified* is True the aliased frequencies
    are suppressed. If command *queue* is specified, execute the kernel on it. If *block* is True,
    wait for the kernel to finish.
    """
    if size % 2:
        raise ValueError('Only even sizes are supported')
    if queue is None:
        queue = cfg.OPENCL.queue
    pixel_size = make_tuple(pixel_size)

    def check_cutoff(ps):
        # Check the sampling
        r_cutoff = compute_aliasing_limit(size, lam, ps, distance, fov=region, fourier=False)
        min_n = 4
        if r_cutoff < min_n:
            LOG.error('Propagator too narrow, propagation distance too small or pixel size too large')
        f_cutoff = compute_aliasing_limit(size, lam, ps, distance, fov=region, fourier=True)
        if f_cutoff < min_n:
            LOG.error('Propagator too wide, propagation distance too large or pixel size too small')

    check_cutoff(pixel_size[1])
    check_cutoff(pixel_size[0])

    out = cl_array.Array(queue, (size, size), cfg.PRECISION.np_cplx)
    if apply_phase_factor:
        phase_factor = np.exp(2 * np.pi * distance.simplified / lam.simplified * 1j)
    else:
        phase_factor = 0 + 0j

    ev = cfg.OPENCL.programs['physics'].propagator(queue,
                                                   (size / 2 + 1, size / 2 + 1),
                                                   None,
                                                   out.data,
                                                   cfg.PRECISION.np_float(distance.simplified),
                                                   cfg.PRECISION.np_float(lam.simplified),
                                                   g_util.make_vfloat2(*pixel_size[::-1].simplified),
                                                   g_util.make_vcomplex(phase_factor),
                                                   np.int32(fresnel))
    if block:
        ev.wait()

    if mollified:
        def compute_sigma_component(ps):
            fwtm = compute_aliasing_limit(size, lam, ps, distance,
                                          fov=size * ps, fourier=True)
            if region is not None:
                fwtm_region = compute_aliasing_limit(size, lam, ps, distance, region,
                                                     fourier=True)
                fwtm = min(fwtm_region, fwtm)
            sigma = fwnm_to_sigma(fwtm, n=10)

            return sigma

        sigma = (compute_sigma_component(pixel_size[0]), compute_sigma_component(pixel_size[1]))
        mollifier = get_gauss_2d(size, sigma, fourier=False, queue=queue, block=block)
        out = out * mollifier

    return out