Пример #1
0
def get_gauss_2d(shape, sigma, pixel_size=1, fourier=False, queue=None, block=False):
    """Get 2D Gaussian of *shape* with standard deviation *sigma* and *pixel_size*. If *fourier* is
    True the fourier transform of it is returned so it is faster for usage by convolution. Use
    command *queue* if specified. If *block* is True, wait for the kernel to finish.
    """
    shape = make_tuple(shape)
    pixel_size = get_magnitude(make_tuple(pixel_size))
    sigma = get_magnitude(make_tuple(sigma))
    LOG.debug('get_gauss_2d, shape: %s, sigma: %s, pixel size: %s, fourier: %s',
              shape, sigma, pixel_size, fourier)

    if queue is None:
        queue = cfg.OPENCL.queue
    out = cl.array.Array(queue, shape, dtype=cfg.PRECISION.np_float)

    if fourier:
        ev = cfg.OPENCL.programs['improc'].gauss_2d_f(queue,
                                                      shape[::-1],
                                                      None,
                                                      out.data,
                                                      g_util.make_vfloat2(sigma[1], sigma[0]),
                                                      g_util.make_vfloat2(pixel_size[1],
                                                      pixel_size[0]))
    else:
        ev = cfg.OPENCL.programs['improc'].gauss_2d(queue,
                                                    shape[::-1],
                                                    None,
                                                    out.data,
                                                    g_util.make_vfloat2(sigma[1], sigma[0]),
                                                    g_util.make_vfloat2(pixel_size[1],
                                                    pixel_size[0]))
    if block:
        ev.wait()

    return out
Пример #2
0
    def transfer(self,
                 shape,
                 pixel_size,
                 energy,
                 exponent=False,
                 offset=None,
                 t=None,
                 queue=None,
                 out=None,
                 check=True,
                 block=False):
        """Transfer function of the element on an image plane of size *shape*, use *pixel_size*,
        *energy*, *offset* is the physical spatial offset of the element as (y, x), transfer at time
        *t*. If *exponent* is true, compute the exponent of the transfer function without applying
        the wavenumber. Use *queue* for OpenCL computations and *out* pyopencl array. If *block* is
        True, wait for the kernel to finish. If *check* is True, the function is checked for
        aliasing artefacts.
        """
        shape = make_tuple(shape, num_dims=2)
        pixel_size = make_tuple(pixel_size, num_dims=2)
        if offset is None:
            offset = (0, 0) * q.m
        if queue is None:
            queue = cfg.OPENCL.queue

        return self._transfer(shape,
                              pixel_size,
                              energy,
                              offset,
                              exponent=exponent,
                              t=t,
                              queue=queue,
                              out=out,
                              check=check,
                              block=block)
Пример #3
0
    def project(self,
                shape,
                pixel_size,
                offset=None,
                t=None,
                queue=None,
                out=None,
                block=False):
        """Project thickness at time *t* to the image plane of size *shape* which is either 1D and
        is extended to (n, n) or is 2D as HxW. *pixel_size* is the point size, also either 1D or 2D.
        *offset* is the physical spatial body offset as (y, x). *queue* is an OpenCL command queue,
        *out* is the pyopencl array used for result. If *block* is True, wait for the kernel to
        finish.
        """
        shape = make_tuple(shape, num_dims=2)
        pixel_size = make_tuple(pixel_size, num_dims=2)
        if offset is None:
            offset = (0, 0) * q.m
        if queue is None:
            queue = cfg.OPENCL.queue

        return self._project(shape,
                             pixel_size,
                             offset,
                             t=t,
                             queue=queue,
                             out=None,
                             block=block)
Пример #4
0
    def transfer_fourier(self, shape, pixel_size, energy, t=None, queue=None,
                         out=None, block=False):
        """Transfer function of the element in Fourier space of size *shape*, use *pixel_size*,
        *energy* and comput the function at time *t*. Use *queue* for OpenCL computations and *out*
        pyopencl array. If *block* is True, wait for the kernel to finish.
        """
        shape = make_tuple(shape, num_dims=2)
        pixel_size = make_tuple(pixel_size, num_dims=2)
        if queue is None:
            queue = cfg.OPENCL.queue

        return self._transfer_fourier(shape, pixel_size, energy, t=t, queue=queue, out=out,
                                      block=block)
Пример #5
0
    def compute_slices(self, shape, pixel_size, queue=None, out=None, offset=None):
        """Compute slices with *shape* as (z, y, x), *pixel_size*. Use *queue* and *out* for
        outuput. Offset is the starting point offset as (x, y, z).
        """
        if queue is None:
            queue = cfg.OPENCL.queue
        if out is None:
            out = cl_array.zeros(queue, shape, dtype=np.uint8)

        pixel_size = make_tuple(pixel_size, num_dims=2)
        v_1, v_2, v_3 = self._make_inputs(queue, pixel_size)
        psm = pixel_size.simplified.magnitude
        max_dx = self.max_triangle_x_diff.simplified.magnitude / psm[1]
        if offset is None:
            offset = gutil.make_vfloat3(0, 0, 0)
        else:
            offset = offset.simplified.magnitude
            offset = gutil.make_vfloat3(offset[0] / psm[1], offset[1] / psm[0], offset[2] / psm[1])

        cfg.OPENCL.programs['mesh'].compute_slices(queue,
                                                   (shape[2], shape[0]),
                                                   None,
                                                   v_1.data,
                                                   v_2.data,
                                                   v_3.data,
                                                   out.data,
                                                   np.int32(shape[1]),
                                                   np.int32(self.num_triangles),
                                                   offset,
                                                   cfg.PRECISION.np_float(max_dx))


        return out
Пример #6
0
def rescale(image, shape, sampler=None, queue=None, out=None, block=False):
    """Rescale *image* to *shape* and use *sampler* which is a :class:`pyopencl.Sampler` instance.
    Use OpenCL *queue* and *out* pyopencl Array. If *block* is True, wait for the copy to finish.
    """
    if cfg.PRECISION.cl_float == 8:
        raise TypeError('Double precision mode not supported')
    shape = make_tuple(shape)
    # OpenCL order
    factor = float(shape[1]) / image.shape[1], float(shape[0]) / image.shape[0]
    LOG.debug('rescale, shape: %s, final_shape: %s, factor: %s', image.shape, shape, factor)

    if queue is None:
        queue = cfg.OPENCL.queue
    if out is None:
        out = cl.array.Array(queue, shape, dtype=cfg.PRECISION.np_float)

    if not sampler:
        sampler = cl.Sampler(cfg.OPENCL.ctx, False, cl.addressing_mode.CLAMP_TO_EDGE, cl.filter_mode.LINEAR)
    image = g_util.get_image(image)

    ev = cfg.OPENCL.programs['improc'].rescale(queue,
                                               shape[::-1],
                                               None,
                                               image,
                                               out.data,
                                               sampler,
                                               g_util.make_vfloat2(*factor))
    if block:
        ev.wait()

    return out
Пример #7
0
def decimate(image, shape, sigma=None, average=False, queue=None, block=False):
    """Decimate *image* so that its dimensions match the final *shape*, which has to be a divisor of
    the original shape. Remove low frequencies by a Gaussian filter with *sigma* pixels. If *sigma*
    is None, use the FWHM of one low resolution pixel. Use command *queue*, if *block* is True, wait
    for the copy to finish.
    """
    if queue is None:
        queue = cfg.OPENCL.queue
    image = g_util.get_array(image, queue=queue)
    shape = make_tuple(shape)
    pow_shape = tuple([next_power_of_two(n) for n in image.shape])
    orig_shape = image.shape
    if image.shape != pow_shape:
        image = pad(image, region=(0, 0) + pow_shape, queue=queue)
    if sigma is None:
        sigma = tuple([fwnm_to_sigma(float(image.shape[i]) / shape[i], n=2) for i in range(2)])

    LOG.debug(
        "decimate, shape: %s, final_shape: %s, sigma: %s, average: %s",
        image.shape,
        shape,
        sigma,
        average,
    )

    fltr = get_gauss_2d(image.shape, sigma, fourier=True, queue=queue, block=block)
    image = image.astype(cfg.PRECISION.np_cplx)
    fft_2(image, queue=queue, block=block)
    image *= fltr
    ifft_2(image, queue=queue, block=block)
    image = crop(image.real, (0, 0) + orig_shape, queue=queue, block=block)

    return bin_image(image, shape, average=average, queue=queue, block=block)
Пример #8
0
    def compute_slices(self,
                       shape,
                       pixel_size,
                       queue=None,
                       out=None,
                       offset=None):
        """Compute slices with *shape* as (z, y, x), *pixel_size*. Use *queue* and *out* for
        outuput. Offset is the starting point offset as (x, y, z).
        """
        if queue is None:
            queue = cfg.OPENCL.queue
        if out is None:
            out = cl_array.zeros(queue, shape, dtype=np.uint8)

        pixel_size = make_tuple(pixel_size, num_dims=2)
        v_1, v_2, v_3 = self._make_inputs(queue, pixel_size)
        psm = pixel_size.simplified.magnitude
        max_dx = self.max_triangle_x_diff.simplified.magnitude / psm[1]
        if offset is None:
            offset = gutil.make_vfloat3(0, 0, 0)
        else:
            offset = offset.simplified.magnitude
            offset = gutil.make_vfloat3(offset[0] / psm[1], offset[1] / psm[0],
                                        offset[2] / psm[1])

        cfg.OPENCL.programs['mesh'].compute_slices(
            queue, (shape[2], shape[0]), None, v_1.data, v_2.data, v_3.data,
            out.data, np.int32(shape[1]), np.int32(self.num_triangles), offset,
            cfg.PRECISION.np_float(max_dx))

        return out
Пример #9
0
 def __init__(
     self,
     energies,
     flux,
     sample_distance,
     size,
     trajectory,
     pixel_size=None,
     phase_profile="plane",
 ):
     """Source with a pre-computed *flux* at given *energies*. *flux* can be a 1D array, in which
     case there is no spatial distribution of intensities, or it can be a 3D array, in which case
     every 2D image *flux[i]* represents spatial intensity distribution for *energies[i]*.
     """
     super(FixedSpectrumSource, self).__init__(sample_distance,
                                               size,
                                               trajectory,
                                               phase_profile=phase_profile)
     if len(flux) != len(energies):
         raise XRaySourceError("Flux must have the same length as energies")
     if flux.ndim == 3 and pixel_size is None:
         raise XRaySourceError(
             "pixel_size must be specified for 3D flux input")
     self._pixel_size = make_tuple(pixel_size, num_dims=2)
     self._energies = energies
     self._flux = flux
Пример #10
0
def rescale(image, shape, sampler=None, queue=None, out=None, block=False):
    """Rescale *image* to *shape* and use *sampler* which is a :class:`pyopencl.Sampler` instance.
    Use OpenCL *queue* and *out* pyopencl Array. If *block* is True, wait for the copy to finish.
    """
    if cfg.PRECISION.cl_float == 8:
        raise TypeError("Double precision mode not supported")
    shape = make_tuple(shape)
    # OpenCL order
    factor = float(shape[1]) / image.shape[1], float(shape[0]) / image.shape[0]
    LOG.debug("rescale, shape: %s, final_shape: %s, factor: %s", image.shape, shape, factor)

    if queue is None:
        queue = cfg.OPENCL.queue
    if out is None:
        out = cl.array.Array(queue, shape, dtype=cfg.PRECISION.np_float)

    if not sampler:
        sampler = cl.Sampler(
            cfg.OPENCL.ctx, False, cl.addressing_mode.CLAMP_TO_EDGE, cl.filter_mode.LINEAR
        )
    image = g_util.get_image(image)

    ev = cfg.OPENCL.programs["improc"].rescale(
        queue, shape[::-1], None, image, out.data, sampler, g_util.make_vfloat2(*factor)
    )
    if block:
        ev.wait()

    return out
Пример #11
0
    def project(self, shape, pixel_size, offset=None, t=None, queue=None, out=None,
                block=False):
        """Project thickness at time *t* to the image plane of size *shape* which is either 1D and
        is extended to (n, n) or is 2D as HxW. *pixel_size* is the point size, also either 1D or 2D.
        *offset* is the physical spatial body offset as (y, x). *queue* is an OpenCL command queue,
        *out* is the pyopencl array used for result. If *block* is True, wait for the kernel to
        finish.
        """
        shape = make_tuple(shape, num_dims=2)
        pixel_size = make_tuple(pixel_size, num_dims=2)
        if offset is None:
            offset = (0, 0) * q.m
        if queue is None:
            queue = cfg.OPENCL.queue

        return self._project(shape, pixel_size, offset, t=t, queue=queue, out=None, block=block)
Пример #12
0
def decimate(image, shape, sigma=None, average=False, queue=None, block=False):
    """Decimate *image* so that its dimensions match the final *shape*, which has to be a divisor of
    the original shape. Remove low frequencies by a Gaussian filter with *sigma* pixels. If *sigma*
    is None, use the FWHM of one low resolution pixel. Use command *queue*, if *block* is True, wait
    for the copy to finish.
    """
    if queue is None:
        queue = cfg.OPENCL.queue
    image = g_util.get_array(image, queue=queue)
    shape = make_tuple(shape)
    pow_shape = tuple([next_power_of_two(n) for n in image.shape])
    orig_shape = image.shape
    if image.shape != pow_shape:
        image = pad(image, region=(0, 0) + pow_shape, queue=queue)
    if sigma is None:
        sigma = tuple([fwnm_to_sigma(float(image.shape[i]) / shape[i], n=2) for i in range(2)])

    LOG.debug('decimate, shape: %s, final_shape: %s, sigma: %s, average: %s', image.shape, shape,
              sigma, average)

    fltr = get_gauss_2d(image.shape, sigma, fourier=True, queue=queue, block=block)
    image = image.astype(cfg.PRECISION.np_cplx)
    fft_2(image, queue=queue, block=block)
    image *= fltr
    ifft_2(image, queue=queue, block=block)
    image = crop(image.real, (0, 0) + orig_shape, queue=queue, block=block)

    return bin_image(image, shape, average=average, queue=queue, block=block)
Пример #13
0
    def project(self,
                shape,
                pixel_size,
                offset=None,
                t=None,
                queue=None,
                out=None,
                block=False):
        """Project thickness at time *t* (if it is None no transformation is applied) to the image
        plane of size *shape* which is either 1D and is extended to (n, n) or is 2D as HxW.
        *pixel_size* is the point size, also either 1D or 2D. *offset* is the physical spatial body
        offset as (y, x). *queue* is an OpenCL command queue, *out* is the pyopencl array used for
        result. If *block* is True, wait for the kernel to finish.
        """
        pixel_size = make_tuple(pixel_size, 2)
        if offset is None:
            offset = (0, 0) * q.m
        if t is not None:
            self.move(t)

        if self.cache_projection:
            if (self._p_cache['time'] is None
                    or np.any(self._p_cache['ps'] != pixel_size)
                    or self._p_cache['shape'] != shape
                    or np.any(self._p_cache['offset'] != offset)):
                moved = True
                self.update_projection_cache(t=t,
                                             shape=shape,
                                             pixel_size=pixel_size,
                                             offset=offset)
            else:
                # 0.99 to make sure we recompute when next_time from cached time is current t
                moved = self.moved(min(self._p_cache['time'], t),
                                   max(self._p_cache['time'], t),
                                   0.99 * min(pixel_size),
                                   bind=False)

            if moved:
                LOG.debug('{} computing projection at {}'.format(self, t))
                self._p_cache['time'] = t
                self._p_cache['projection'] = super(MovableBody, self).project(
                    shape,
                    pixel_size,
                    offset=offset,
                    t=t,
                    queue=queue,
                    out=None,
                    block=block)
            projection = self._p_cache['projection']
        else:
            projection = super(MovableBody, self).project(shape,
                                                          pixel_size,
                                                          offset=offset,
                                                          t=t,
                                                          queue=queue,
                                                          out=None,
                                                          block=block)

        return projection
Пример #14
0
    def get_extrema(sgn):
        func = np.max if sgn > 0 else np.min
        x_ps = util.make_tuple(pixel_size)[1]
        res = [(ball.position[2] + sgn *
                (2 * ball.radius + x_ps)).simplified.magnitude
               for ball in metaballs]

        return func(res)
Пример #15
0
def project_metaballs_naive(metaballs,
                            shape,
                            pixel_size,
                            offset=None,
                            z_step=None,
                            queue=None,
                            out=None,
                            block=False):
    """Project a list of :class:`.MetaBall` on an image plane with *shape*, *pixel_size*. *z_step*
    is the physical step in the z-dimension, if not specified it is the same as *pixel_size*.
    *offset* is the physical spatial body offset as (y, x). Use OpenCL *queue* and *out* pyopencl
    Array instance for returning the result. If *block* is True, wait for the kernel to finish.
    """
    def get_extrema(sgn):
        func = np.max if sgn > 0 else np.min
        x_ps = util.make_tuple(pixel_size)[1]
        res = [(ball.position[2] + sgn *
                (2 * ball.radius + x_ps)).simplified.magnitude
               for ball in metaballs]

        return func(res)

    if offset is None:
        offset = (0, 0) * q.m
    if not queue:
        queue = cfg.OPENCL.queue
    if out is None:
        out = cl_array.Array(queue, shape, cfg.PRECISION.np_float)

    string = b"".join([body.pack() for body in metaballs])
    data = np.fromstring(string, dtype=np.float32)
    data = cl_array.to_device(queue, data)
    n, m = shape
    ps = util.make_tuple(pixel_size.simplified.magnitude)
    z_step = ps[1] if z_step is None else z_step.simplified.magnitude

    z_range = get_extrema(-1), get_extrema(1)
    offset = g_util.make_vfloat2(*offset.simplified.magnitude[::-1])

    ev = cfg.OPENCL.programs["geometry"].naive_metaballs(
        cfg.OPENCL.queue,
        (m, n),
        None,
        out.data,
        data.data,
        np.int32(len(metaballs)),
        offset,
        g_util.make_vfloat2(*z_range),
        cfg.PRECISION.np_float(z_step),
        g_util.make_vfloat2(*ps[::-1]),
        np.int32(True),
    )
    if block:
        ev.wait()

    return out
Пример #16
0
def get_gauss_2d(shape, sigma, pixel_size=None, fourier=False):
    shape = make_tuple(shape)
    sigma = get_magnitude(make_tuple(sigma))
    if pixel_size is None:
        pixel_size = (1, 1)
    else:
        pixel_size = get_magnitude(make_tuple(pixel_size))

    if fourier:
        i = np.fft.fftfreq(shape[1]) / pixel_size[1]
        j = np.fft.fftfreq(shape[0]) / pixel_size[0]
        i, j = np.meshgrid(i, j)

        return np.exp(-2 * np.pi ** 2 * ((i * sigma[1]) ** 2 + (j * sigma[0]) ** 2))
    else:
        x = (np.arange(shape[1]) - shape[1] / 2) * pixel_size[1]
        y = (np.arange(shape[0]) - shape[0] / 2) * pixel_size[0]
        x, y = np.meshgrid(x, y)
        gauss = np.exp(- x ** 2 / (2. * sigma[1] ** 2) - y ** 2 / (2. * sigma[0] ** 2))

        return np.fft.ifftshift(gauss)
Пример #17
0
def get_gauss_2d(shape, sigma, pixel_size=None, fourier=False):
    shape = make_tuple(shape)
    sigma = get_magnitude(make_tuple(sigma))
    if pixel_size is None:
        pixel_size = (1, 1)
    else:
        pixel_size = get_magnitude(make_tuple(pixel_size))

    if fourier:
        i = np.fft.fftfreq(shape[1]) / pixel_size[1]
        j = np.fft.fftfreq(shape[0]) / pixel_size[0]
        i, j = np.meshgrid(i, j)

        return np.exp(-2 * np.pi ** 2 * ((i * sigma[1]) ** 2 + (j * sigma[0]) ** 2))
    else:
        x = (np.arange(shape[1]) - shape[1] // 2) * pixel_size[1]
        y = (np.arange(shape[0]) - shape[0] // 2) * pixel_size[0]
        x, y = np.meshgrid(x, y)
        gauss = np.exp(-(x ** 2) / (2.0 * sigma[1] ** 2) - y ** 2 / (2.0 * sigma[0] ** 2))

        return np.fft.ifftshift(gauss)
Пример #18
0
def main():
    args = parse_args()
    syris.init(device_index=0)
    shape = (args.n, args.n)
    pixel_size = 1 * q.um

    if args.method == "random":
        # Random metaballs creation
        metaballs, objects_all = create_metaballs_random(
            args.n,
            pixel_size,
            args.num,
            args.min_radius,
            args.max_radius,
            distance_from_center=args.distance_from_center,
        )
    elif args.method == "file":
        # 1e6 because packing converts to meters
        values = np.fromfile(args.input, dtype=np.float32) * 1e6
        metaballs, objects_all = create_metaballs(
            values.reshape(len(values) // 4, 4), pixel_size)
    else:
        distance = args.distance or args.n / 4
        positions = [
            (args.n / 2 - distance, args.n / 2, 0, args.n / 6),
            (args.n / 2 + distance, args.n / 2, 0, args.n / 6),
        ]
        metaballs, objects_all = create_metaballs(positions, pixel_size)

    if args.output:
        with open(args.output, mode="wb") as out_file:
            out_file.write(objects_all)

    z_min, z_max = get_z_range(metaballs)
    print("z min, max:", z_min.rescale(q.um), z_max.rescale(q.um),
          args.n * pixel_size + z_min)

    if args.algorithm == "fast":
        traj = Trajectory([(0, 0, 0)] * q.m)
        comp = MetaBalls(traj, metaballs)
        thickness = comp.project(shape, pixel_size).get()
    else:
        print("Z steps:",
              int(((z_max - z_min) / pixel_size).simplified.magnitude + 0.5))
        thickness = project_metaballs_naive(metaballs, shape,
                                            make_tuple(pixel_size)).get()

    if args.output_thickness:
        imageio.imwrite(args.output_thickness, thickness)

    show(thickness)
    plt.show()
Пример #19
0
def make_sphere(n, radius, pixel_size=1 * q.m, material=None, queue=None):
    """Make a sphere with image shape (*n*, *n*), *radius* and *pixel_size*. Sphere center is in n /
    2 + 0.5, which means between two adjacent pixels. *pixel_size*, *material* and *queue*, which is
    an OpenCL command queue, are used to create :class:`.StaticBody`.
    """
    pixel_size = make_tuple(pixel_size, num_dims=2)
    image = np.zeros((n, n), dtype=cfg.PRECISION.np_float)
    y, x = np.mgrid[-n // 2 : n // 2, -n // 2 : n // 2]
    x = (x + 0.5) * pixel_size[1].simplified.magnitude
    y = (y + 0.5) * pixel_size[0].simplified.magnitude
    radius = radius.simplified.magnitude
    valid = np.where(x ** 2 + y ** 2 < radius ** 2)
    image[valid] = 2 * np.sqrt(radius ** 2 - x[valid] ** 2 - y[valid] ** 2)

    return StaticBody(image * q.m, pixel_size, material=material, queue=queue)
Пример #20
0
def test_make_tuple():
    assert make_tuple(1) == (1, 1)
    assert make_tuple(1, num_dims=3) == (1, 1, 1)
    assert make_tuple((1, 2)) == (1, 2)
    assert_raises(ValueError, make_tuple, (1, 1), num_dims=3)

    assert tuple(make_tuple(1 * q.m).simplified.magnitude) == (1, 1)
    assert tuple(make_tuple(1 * q.m,
                            num_dims=3).simplified.magnitude) == (1, 1, 1)
    assert tuple(make_tuple((1, 2) * q.m).simplified.magnitude) == (1, 2)
    assert_raises(ValueError, make_tuple, (1, 1) * q.mm, num_dims=3)
Пример #21
0
    def _transfer(
        self,
        shape,
        pixel_size,
        energy,
        offset,
        exponent=False,
        t=None,
        queue=None,
        out=None,
        check=True,
        block=False,
    ):
        """Compute the flat field wavefield. Returned *out* array is different from the input
        one.
        """
        if queue is None:
            queue = cfg.OPENCL.queue
        if out is None:
            out = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_cplx)

        ps = make_tuple(pixel_size)
        if t is None:
            x, y, z = self.trajectory.control_points.simplified.magnitude[0]
        else:
            x, y, z = self.trajectory.get_point(t).simplified.magnitude
        x += offset[1].simplified.magnitude
        y += offset[0].simplified.magnitude
        center = (x, y, z)
        phase = self.phase_profile != "plane"
        parabola = self.phase_profile == "parabola"
        compute_exponent = exponent or check and phase

        self._transfer_real(shape, center, ps, energy, compute_exponent, phase,
                            parabola, out, queue, block)

        if compute_exponent:
            if check and phase and not is_wavefield_sampling_ok(out,
                                                                queue=queue):
                LOG.error("Insufficient beam phase sampling")
            if not exponent:
                out = clmath.exp(out, queue=queue)

        return out
Пример #22
0
    def __init__(self,
                 filename,
                 sample_distance,
                 dE,
                 size,
                 pixel_size,
                 trajectory,
                 phase_profile='sphere',
                 fluctuation=None):

        super(SpectraSource, self).__init__()
        self.sample_distance = sample_distance.simplified
        self.dE = dE
        self.pixel_size = make_tuple(pixel_size, num_dims=2)
        self.size = size.simplified
        self.trajectory = trajectory
        self._phase_profile = None
        self.phase_profile = phase_profile
        self.fluctuation = fluctuation
        self._spline2d = self.import_spectra_file(filename)
Пример #23
0
def main():
    args = parse_args()
    syris.init(device_index=0)
    shape = (args.n, args.n)
    pixel_size = 1 * q.um

    if args.method == 'random':
        # Random metaballs creation
        metaballs, objects_all = create_metaballs_random(args.n, pixel_size, args.num,
                                                         args.min_radius, args.max_radius)
    elif args.method == 'file':
        # 1e6 because packing converts to meters
        values = np.fromfile(args.input, dtype=np.float32) * 1e6
        metaballs, objects_all = create_metaballs(values.reshape(len(values) / 4, 4))
    else:
        distance = args.distance or args.n / 4
        positions = [(args.n / 2 - distance, args.n / 2, 0, args.n / 6),
                     (args.n / 2 + distance, args.n / 2, 0, args.n / 6)]
        metaballs, objects_all = create_metaballs(positions)

    if args.output:
        with open(args.output, mode='wb') as out_file:
            out_file.write(objects_all)

    z_min, z_max = get_z_range(metaballs)
    print 'z min, max:', z_min.rescale(q.um), z_max.rescale(q.um), args.n * pixel_size + z_min

    if args.algorithm == 'fast':
        traj = Trajectory([(0, 0, 0)] * q.m)
        comp = MetaBalls(traj, metaballs)
        thickness = comp.project(shape, pixel_size).get()
    else:
        print 'Z steps:', int(((z_max - z_min) / pixel_size).simplified.magnitude + 0.5)
        thickness = project_metaballs_naive(metaballs, shape, make_tuple(pixel_size)).get()

    if args.output_thickness:
        save_image(args.output_thickness, thickness)

    show(thickness)
    plt.show()
Пример #24
0
    def __init__(self,
                 electron_energy,
                 el_current,
                 magnetic_field,
                 sample_distance,
                 dE,
                 size,
                 pixel_size,
                 trajectory,
                 profile_approx=True,
                 phase_profile='plane'):
        """The parameters are *electron_energy*, electric *el_current*, *magnetic_field*, place it
        into *sample_distance* (distance between the source and a sample), take into account energy
        spacing *dE* which sets the amount of photons obtained for an energy to be:

        .. math::

            \Phi = \int_{E - dE / 2}^{E + dE / 2} \Phi(E) dE

        Set its *size* (y, x) specified as FWHM and approximate it by a Gaussian. *pixel_size* is
        the effective pixel size. *trajectory* is the trajectory defining the source position in
        space and time. If *profile_approx* is True, the profile at a given vertical observation
        angle will not be integrated over the relevant energies but will be calculated for the mean
        energy and multiplied by *dE*. *phase_profile* can be one of 'plane', 'parabola' and
        'sphere', where plane denotes constant phase profile (plane wave approximation) and parabola
        is the parabolic approximation of the real spherical profile.
        """

        super(BendingMagnet, self).__init__()
        self.electron_energy = electron_energy.simplified
        self.el_current = el_current.simplified
        self.magnetic_field = magnetic_field
        self.sample_distance = sample_distance.simplified
        self.dE = dE
        self.size = size.simplified
        self.pixel_size = make_tuple(pixel_size, num_dims=2)
        self.trajectory = trajectory
        self.profile_approx = profile_approx
        self._phase_profile = None
        self.phase_profile = phase_profile
Пример #25
0
    def project(self, shape, pixel_size, offset=None, t=None, queue=None, out=None,
                block=False):
        """Project thickness at time *t* (if it is None no transformation is applied) to the image
        plane of size *shape* which is either 1D and is extended to (n, n) or is 2D as HxW.
        *pixel_size* is the point size, also either 1D or 2D. *offset* is the physical spatial body
        offset as (y, x). *queue* is an OpenCL command queue, *out* is the pyopencl array used for
        result. If *block* is True, wait for the kernel to finish.
        """
        pixel_size = make_tuple(pixel_size, 2)
        if offset is None:
            offset = (0, 0) * q.m
        if t is not None:
            self.move(t)

        if self.cache_projection:
            if (self._p_cache['time'] is None or np.any(self._p_cache['ps'] != pixel_size) or
                    self._p_cache['shape'] != shape or np.any(self._p_cache['offset'] != offset)):
                moved = True
                self.update_projection_cache(t=t, shape=shape, pixel_size=pixel_size, offset=offset)
            else:
                # 0.99 to make sure we recompute when next_time from cached time is current t
                moved = self.moved(min(self._p_cache['time'], t),
                                   max(self._p_cache['time'], t), 0.99 * min(pixel_size),
                                   bind=False)

            if moved:
                LOG.debug('{} computing projection at {}'.format(self, t))
                self._p_cache['time'] = t
                self._p_cache['projection'] = super(MovableBody, self).project(shape, pixel_size,
                                                                               offset=offset,
                                                                               t=t, queue=queue,
                                                                               out=None,
                                                                               block=block)
            projection = self._p_cache['projection']
        else:
            projection = super(MovableBody, self).project(shape, pixel_size, offset=offset,
                                                          t=t, queue=queue, out=None, block=block)

        return projection
Пример #26
0
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
Пример #27
0
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.warning(
                "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.warning(
                "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
Пример #28
0
    def _transfer(self,
                  shape,
                  pixel_size,
                  energy,
                  offset,
                  exponent=False,
                  t=None,
                  queue=None,
                  out=None,
                  check=True,
                  block=False):
        """Compute the flat field wavefield. Returned *out* array is different from the input one."""
        if queue is None:
            queue = cfg.OPENCL.queue

        ps = make_tuple(pixel_size)
        if t is None:
            x, y, z = self.trajectory.control_points.simplified.magnitude[0]
        else:
            x, y, z = self.trajectory.get_point(t).simplified.magnitude
        x += offset[1].simplified.magnitude
        y += offset[0].simplified.magnitude
        center = (x, y, z)
        cl_center = gutil.make_vfloat3(*center)
        cl_ps = gutil.make_vfloat2(*pixel_size.simplified.magnitude[::-1])
        fov = np.arange(0, shape[0]) * ps[0] - y * q.m
        angles = np.arctan((fov / self.sample_distance).simplified)
        profile = self._create_vertical_profile(energy, angles, ps[0]).rescale(
            1 / q.s).magnitude

        profile = cl_array.to_device(queue,
                                     profile.astype(cfg.PRECISION.np_float))
        if out is None:
            out = cl_array.Array(queue, shape, dtype=cfg.PRECISION.np_cplx)

        z_sample = self.sample_distance.simplified.magnitude
        lam = energy_to_wavelength(energy).simplified.magnitude
        phase = self.phase_profile != 'plane'
        parabola = self.phase_profile == 'parabola'
        if exponent or check and phase:
            ev = cfg.OPENCL.programs['physics'].make_flat(
                queue, shape[::-1], None, out.data, profile.data, cl_center,
                cl_ps, cfg.PRECISION.np_float(z_sample),
                cfg.PRECISION.np_float(lam), np.int32(True), np.int32(phase),
                np.int32(parabola))
            if check and phase and not is_wavefield_sampling_ok(out,
                                                                queue=queue):
                LOG.error('Insufficient beam phase sampling')
            if not exponent:
                out = clmath.exp(out, queue=queue)
        else:
            ev = cfg.OPENCL.programs['physics'].make_flat(
                queue, shape[::-1], None,
                out.data, profile.data, cl_center, cl_ps,
                cfg.PRECISION.np_float(z_sample), cfg.PRECISION.np_float(lam),
                np.int32(exponent), np.int32(phase), np.int32(parabola))

        if block:
            ev.wait()

        return out
Пример #29
0
 def __init__(self, thickness, pixel_size, material=None, queue=None):
     super(StaticBody, self).__init__(material)
     self.thickness = g_util.get_array(thickness.simplified.magnitude, queue=queue)
     self.pixel_size = make_tuple(pixel_size, num_dims=2)