4
How to use struct types with PyOpenCL
5
-------------------------------------
7
We import and initialize PyOpenCL as usual:
12
>>> import numpy as np
13
>>> import pyopencl as cl
14
>>> import pyopencl.tools
15
>>> import pyopencl.array
17
>>> ctx = cl.create_some_context(interactive=False)
18
>>> queue = cl.CommandQueue(ctx)
20
Then, suppose we would like to declare a struct consisting of an integer and a
21
floating point number. We first create a :class:`numpy.dtype` along these
26
>>> my_struct = np.dtype([("field1", np.int32), ("field2", np.float32)])
28
[('field1', '<i4'), ('field2', '<f4')]
32
Not all :mod:`numpy` dtypes are supported yet. For example strings (and
33
generally things that have a shape of their own) are not supported.
35
Since OpenCL C may have a different opinion for :mod:`numpy` on how the struct
36
should be laid out, for example because of `alignment
37
<https://en.wikipedia.org/wiki/Data_structure_alignment>`_. So as a first step, we
38
match our dtype against CL's version:
42
>>> my_struct, my_struct_c_decl = cl.tools.match_dtype_to_c_struct(
43
... ctx.devices[0], "my_struct", my_struct)
44
>>> print my_struct_c_decl
52
We then tell PyOpenCL about our new type.
56
>>> my_struct = cl.tools.get_or_register_dtype("my_struct", my_struct)
58
Next, we can create some data of that type on the host and transfer it to
63
>>> ary_host = np.empty(20, my_struct)
64
>>> ary_host["field1"].fill(217)
65
>>> ary_host["field2"].fill(1000)
66
>>> ary_host[13]["field2"] = 12
68
[(217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)
69
(217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)
70
(217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 12.0) (217, 1000.0)
71
(217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)]
73
>>> ary = cl.array.to_device(queue, ary_host)
75
We can then operate on the array with our own kernels:
79
>>> prg = cl.Program(ctx, my_struct_c_decl + """
80
... __kernel void set_to_1(__global my_struct *a)
82
... a[get_global_id(0)].field1 = 1;
86
>>> evt = prg.set_to_1(queue, ary.shape, None, ary.data)
88
[(1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
89
(1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
90
(1, 1000.0) (1, 12.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
91
(1, 1000.0) (1, 1000.0)]
93
as well as with PyOpenCL's built-in operations:
95
>>> from pyopencl.elementwise import ElementwiseKernel
96
>>> elwise = ElementwiseKernel(ctx, "my_struct *a", "a[i].field1 = 2;",
97
... preamble=my_struct_c_decl)
100
[(2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
101
(2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
102
(2, 1000.0) (2, 12.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
103
(2, 1000.0) (2, 1000.0)]