xobjects 0.6.5__tar.gz → 0.6.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. xobjects-0.6.6/.github/workflows/black.yml +10 -0
  2. xobjects-0.6.6/.gitignore +13 -0
  3. xobjects-0.6.6/.pre-commit-config.yaml +12 -0
  4. xobjects-0.6.6/.readthedocs.yaml +20 -0
  5. xobjects-0.6.6/PKG-INFO +404 -0
  6. xobjects-0.6.6/README.md +375 -0
  7. xobjects-0.6.6/contributors_and_credits.txt +7 -0
  8. xobjects-0.6.6/docs/Makefile +20 -0
  9. xobjects-0.6.6/docs/architecture/contexts.rst +164 -0
  10. xobjects-0.6.6/docs/architecture/types.rst +179 -0
  11. xobjects-0.6.6/docs/architecture.rst +16 -0
  12. xobjects-0.6.6/docs/conf.py +278 -0
  13. xobjects-0.6.6/docs/index.rst +79 -0
  14. xobjects-0.6.6/docs/make.bat +35 -0
  15. xobjects-0.6.6/docs/quickstart.rst +2 -0
  16. xobjects-0.6.6/docs/reference.rst +8 -0
  17. xobjects-0.6.6/examples/api_def.py +28 -0
  18. xobjects-0.6.6/examples/api_init.py +101 -0
  19. xobjects-0.6.6/examples/capi_example.c +100 -0
  20. xobjects-0.6.6/examples/check_assembly.c +101 -0
  21. xobjects-0.6.6/examples/ex_array_init_perf.py +42 -0
  22. xobjects-0.6.6/examples/ex_cpugpu.py +46 -0
  23. xobjects-0.6.6/examples/ex_nested_ref.py +49 -0
  24. xobjects-0.6.6/examples/ex_ref_cpu.py +52 -0
  25. xobjects-0.6.6/examples/ex_struct_cpu.py +39 -0
  26. xobjects-0.6.6/examples/ex_unionref_cpu.py +49 -0
  27. xobjects-0.6.6/examples/ex_unionref_method.py +120 -0
  28. xobjects-0.6.6/examples/init_soa.py +67 -0
  29. xobjects-0.6.6/examples/issue_with_two_pyopencl_contexts.py +18 -0
  30. xobjects-0.6.6/examples/kernel_basics/kernel_cffi.py +54 -0
  31. xobjects-0.6.6/examples/kernel_basics/kernel_cupy.py +42 -0
  32. xobjects-0.6.6/examples/kernel_basics/kernel_pyopencl.py +48 -0
  33. xobjects-0.6.6/examples/opencl_offsets.py +38 -0
  34. xobjects-0.6.6/examples/simple_kernel.py +59 -0
  35. xobjects-0.6.6/examples/sixtracklib.py +80 -0
  36. xobjects-0.6.6/mktest +1 -0
  37. xobjects-0.6.6/release.sh +20 -0
  38. xobjects-0.6.6/requirements.txt +3 -0
  39. xobjects-0.6.6/tests/__init__.py +4 -0
  40. xobjects-0.6.6/tests/notest_capi.py +208 -0
  41. xobjects-0.6.6/update_cprght_statement.py +49 -0
  42. xobjects-0.6.6/xobjects/_version.py +1 -0
  43. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/context_cpu.py +24 -21
  44. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/context_cupy.py +100 -12
  45. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/headers/atomicadd.h +17 -1
  46. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/struct.py +6 -5
  47. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/test_helpers.py +3 -1
  48. xobjects-0.6.6/xobjects.egg-info/PKG-INFO +404 -0
  49. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects.egg-info/SOURCES.txt +39 -0
  50. xobjects-0.6.5/PKG-INFO +0 -39
  51. xobjects-0.6.5/README.md +0 -10
  52. xobjects-0.6.5/xobjects/_version.py +0 -1
  53. xobjects-0.6.5/xobjects.egg-info/PKG-INFO +0 -39
  54. {xobjects-0.6.5 → xobjects-0.6.6}/Architecture.md +0 -0
  55. {xobjects-0.6.5 → xobjects-0.6.6}/LICENSE +0 -0
  56. {xobjects-0.6.5 → xobjects-0.6.6}/MANIFEST.in +0 -0
  57. {xobjects-0.6.5 → xobjects-0.6.6}/pyproject.toml +0 -0
  58. {xobjects-0.6.5 → xobjects-0.6.6}/setup.cfg +0 -0
  59. {xobjects-0.6.5 → xobjects-0.6.6}/setup.py +0 -0
  60. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_align.py +0 -0
  61. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_array.py +0 -0
  62. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_buffer.py +0 -0
  63. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_capi.py +0 -0
  64. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_chunk.py +0 -0
  65. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_common.py +0 -0
  66. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_context_opencl.py +0 -0
  67. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_hybrid_class.py +0 -0
  68. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_kernel.py +0 -0
  69. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_linked_array.py +0 -0
  70. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_nplike_arrays.py +0 -0
  71. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_ref.py +0 -0
  72. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_scalars.py +0 -0
  73. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_shared_memory.py +0 -0
  74. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_strides.py +0 -0
  75. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_string.py +0 -0
  76. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_struct.py +0 -0
  77. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_to_dict.py +0 -0
  78. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_typeutils.py +0 -0
  79. {xobjects-0.6.5 → xobjects-0.6.6}/tests/test_unionref.py +0 -0
  80. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/__init__.py +0 -0
  81. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/_patch_pyopencl_array.py +0 -0
  82. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/array.py +0 -0
  83. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/capi.py +0 -0
  84. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/context.py +0 -0
  85. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/context_pyopencl.py +0 -0
  86. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/general.py +0 -0
  87. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/headers/common.h +0 -0
  88. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/hybrid_class.py +0 -0
  89. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/linkedarray.py +0 -0
  90. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/ref.py +0 -0
  91. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/scalar.py +0 -0
  92. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/specialize_source.py +0 -0
  93. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/string.py +0 -0
  94. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/typeutils.py +0 -0
  95. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects/union.py +0 -0
  96. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects.egg-info/dependency_links.txt +0 -0
  97. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects.egg-info/entry_points.txt +0 -0
  98. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects.egg-info/requires.txt +0 -0
  99. {xobjects-0.6.5 → xobjects-0.6.6}/xobjects.egg-info/top_level.txt +0 -0
@@ -0,0 +1,10 @@
1
+ name: Lint
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ lint:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - uses: psf/black@26.1.0
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ *.swp
5
+ *.egg-info/
6
+ docs/_build
7
+ cov_html
8
+ .vscode
9
+ .pytest_cache
10
+ .coverage
11
+ .idea
12
+ *.c
13
+ **/.DS_Store
@@ -0,0 +1,12 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v4.5.0
4
+ hooks:
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+ - repo: https://github.com/psf/black
9
+ rev: 23.10.1
10
+ hooks:
11
+ - id: black
12
+ language_version: python3 # Should be a command that runs python3.6+
@@ -0,0 +1,20 @@
1
+ # .readthedocs.yaml
2
+ # Read the Docs configuration file
3
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4
+
5
+ # Required
6
+ version: 2
7
+
8
+ # Build documentation in the docs/ directory with Sphinx
9
+ sphinx:
10
+ configuration: docs/conf.py
11
+
12
+ # Optionally build your docs in additional formats such as PDF
13
+ formats:
14
+ - pdf
15
+
16
+ # Optionally set the version of Python and requirements required to build your docs
17
+ python:
18
+ version: 3.7
19
+ # install:
20
+ # - requirements: docs/requirements.txt
@@ -0,0 +1,404 @@
1
+ Metadata-Version: 2.4
2
+ Name: xobjects
3
+ Version: 0.6.6
4
+ Summary: In-memory serialization and code generator for CPU and GPU
5
+ Home-page: https://xsuite.readthedocs.io/
6
+ Download-URL: https://pypi.python.org/pypi/xobjects
7
+ Author: Riccardo De Maria
8
+ Author-email: Riccardo De Maria <riccardo.de.maria@cern.ch>
9
+ License-Expression: Apache-2.0
10
+ Project-URL: Homepage, https://xsuite.readthedocs.io/
11
+ Project-URL: Bug Tracker, https://github.com/xsuite/xsuite/issues
12
+ Project-URL: Documentation, https://xsuite.readthedocs.io/
13
+ Project-URL: Source Code, https://github.com/xsuite/xobjects
14
+ Project-URL: Download, https://pypi.python.org/pypi/xobjects
15
+ Requires-Python: >=3.7
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy
19
+ Requires-Dist: cffi
20
+ Requires-Dist: scipy
21
+ Provides-Extra: tests
22
+ Requires-Dist: pytest; extra == "tests"
23
+ Requires-Dist: pytest-mock; extra == "tests"
24
+ Dynamic: author
25
+ Dynamic: download-url
26
+ Dynamic: home-page
27
+ Dynamic: license-file
28
+ Dynamic: requires-python
29
+
30
+ # Xobjects
31
+
32
+ Xobjects is a low-level Python package for defining structured data that can be
33
+ stored in CPU or GPU memory and accessed from generated C APIs. It is used by
34
+ the Xsuite ecosystem as the memory, serialization, and kernel-compilation layer,
35
+ but it can also be used directly when a project needs the same data layout from
36
+ Python and from compiled CPU, CUDA, or OpenCL code.
37
+
38
+ The main building blocks are:
39
+
40
+ - contexts, which select the execution and memory backend;
41
+ - buffers, which own memory allocated by a context;
42
+ - xobject data types, which describe the binary layout of scalars, arrays,
43
+ structures, strings, and references;
44
+ - kernels, which bind C-like source code to typed Python callables.
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ python -m pip install xobjects
50
+ ```
51
+
52
+ For local development:
53
+
54
+ ```bash
55
+ git clone https://github.com/xsuite/xobjects.git
56
+ cd xobjects
57
+ python -m pip install -e ".[tests]"
58
+ ```
59
+
60
+ GPU contexts require their corresponding runtime packages and drivers:
61
+
62
+ - `ContextCpu` uses NumPy arrays and CFFI-compiled CPU kernels.
63
+ - `ContextCupy` uses CuPy arrays and CUDA kernels.
64
+ - `ContextPyopencl` uses PyOpenCL arrays and OpenCL kernels.
65
+
66
+ OpenMP support for CPU kernels requires an OpenMP-capable compiler and runtime
67
+ to be installed in the environment.
68
+
69
+
70
+ ## Development
71
+
72
+ Run the test suite with:
73
+
74
+ ```bash
75
+ pytest tests
76
+ ```
77
+
78
+ Some tests and examples need optional GPU dependencies or a configured GPU
79
+ runtime. CPU-only development can still run the regular test subset that does
80
+ not require those contexts. Which tests are run is specified by the `XOBJECTS_TEST_CONTEXTS` flag. By default all contexts supported by the system are used, but this can be narrowed down, e.g. only the CPU serial and OpenMP tests will be run if `XOBJECTS_TEST_CONTEXTS=ContextCpu;ContextCpu:auto` is set.
81
+
82
+ ## Contributing
83
+
84
+ The project uses Black for Python formatting and provides a pre-commit
85
+ configuration. Install the pre-commit hooks before committing:
86
+
87
+ ```bash
88
+ pip install pre-commit
89
+ pre-commit install
90
+ ```
91
+
92
+ This will run formatting hooks on every commit.
93
+
94
+
95
+ ## Contexts and Buffers
96
+
97
+ A context represents where data lives and where kernels execute. A buffer is a
98
+ memory allocation owned by a context. Xobjects can allocate a new buffer
99
+ implicitly, or they can be placed explicitly in an existing buffer so that
100
+ several objects share one memory range.
101
+
102
+ ```python
103
+ import xobjects as xo
104
+
105
+ ctx = xo.ContextCpu()
106
+ buffer = ctx.new_buffer(capacity=1024)
107
+
108
+ class Point(xo.Struct):
109
+ x = xo.Float64
110
+ y = xo.Float64
111
+
112
+ p1 = Point(x=1.0, y=2.0, _context=ctx) # new buffer on ctx
113
+ p2 = Point(x=3.0, y=4.0, _buffer=buffer) # explicit buffer
114
+
115
+ print(p1._context)
116
+ print(p2._buffer is buffer)
117
+ ```
118
+
119
+ If no `_context` or `_buffer` is supplied, Xobjects uses the default CPU
120
+ context. Passing `_context` creates a new buffer in that context. Passing
121
+ `_buffer` places the object in that buffer. Passing `_offset` is supported for
122
+ advanced use, but it must be used carefully because overlapping allocations can
123
+ corrupt objects in the same buffer.
124
+
125
+ Context arrays can be converted to and from NumPy arrays through the context:
126
+
127
+ ```python
128
+ import numpy as np
129
+ import xobjects as xo
130
+
131
+ ctx = xo.ContextCpu()
132
+ host = np.arange(8, dtype=np.float64)
133
+
134
+ on_context = ctx.nparray_to_context_array(host)
135
+ back_on_host = ctx.nparray_from_context_array(on_context)
136
+ ```
137
+
138
+ On GPU contexts, array attributes expose NumPy-like GPU arrays. Some NumPy
139
+ operations require an explicit copy back to host memory with
140
+ `nparray_from_context_array`.
141
+
142
+ `ContextCpu` can compile kernels with OpenMP support when it is created with
143
+ `omp_num_threads` different from `0`:
144
+
145
+ ```python
146
+ import xobjects as xo
147
+
148
+ ctx = xo.ContextCpu(omp_num_threads="auto") # let OpenMP choose the thread count
149
+ ctx = xo.ContextCpu(omp_num_threads=4) # use four OpenMP threads
150
+ ctx = xo.ContextCpu(omp_num_threads=0) # serial CPU execution
151
+ ```
152
+
153
+ ## Defining Data
154
+
155
+ Xobjects data types describe a stable binary layout. The same definition drives
156
+ Python accessors, buffer allocation, serialization helpers, and generated C
157
+ accessors.
158
+
159
+ ### Scalars
160
+
161
+ Scalar types wrap fixed-width NumPy dtypes and C types:
162
+
163
+ - floating point: `Float64`, `Float32`;
164
+ - signed integers: `Int64`, `Int32`, `Int16`, `Int8`;
165
+ - unsigned integers: `UInt64`, `UInt32`, `UInt16`, `UInt8`.
166
+
167
+ ```python
168
+ import xobjects as xo
169
+
170
+ value = xo.Float64(3.5)
171
+ index = xo.Int64(7)
172
+ ```
173
+
174
+ ### Arrays
175
+
176
+ Arrays are declared by indexing an item type:
177
+
178
+ ```python
179
+ import xobjects as xo
180
+
181
+ Vector = xo.Float64[3] # fixed-length array
182
+ Series = xo.Float64[:] # one dynamic dimension
183
+ Matrix = xo.Float64[:, 3]
184
+
185
+ v = Vector([1.0, 2.0, 3.0])
186
+ s = Series([0.0, 1.0, 2.0, 3.0])
187
+ m = Matrix([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
188
+ ```
189
+
190
+ Arrays can contain scalars, structs, strings, and references. Fixed-size arrays
191
+ have a static footprint; dynamic arrays store size and layout metadata in the
192
+ buffer before their data.
193
+
194
+ ### Structs
195
+
196
+ `Struct` classes define named fields stored together in one xobject.
197
+
198
+ ```python
199
+ import xobjects as xo
200
+
201
+ class Particle(xo.Struct):
202
+ x = xo.Float64
203
+ px = xo.Float64
204
+ state = xo.Int64
205
+
206
+ particle = Particle(x=1.0, px=0.01, state=1)
207
+ particle.x += 0.5
208
+ ```
209
+
210
+ Fields can be scalars, arrays, nested structs, strings, `Ref` values, or
211
+ `UnionRef` values. Dynamic fields are stored through offsets inside the same
212
+ buffer-backed object.
213
+
214
+ ### Hybrid Classes
215
+
216
+ `HybridClass` is a convenience layer for user-facing Python classes that keep
217
+ regular Python methods and attributes while storing selected fields in an
218
+ underlying xobject. The C-visible fields are declared in `_xofields`.
219
+
220
+ ```python
221
+ import xobjects as xo
222
+
223
+ class Record(xo.HybridClass):
224
+ _xofields = {
225
+ "value": xo.Float64,
226
+ "samples": xo.Float64[:],
227
+ }
228
+
229
+ def add_offset(self, offset):
230
+ self.value += offset
231
+
232
+ record = Record(value=1.5, samples=[0.0, 1.0, 2.0])
233
+ record.add_offset(0.5)
234
+
235
+ print(record.value)
236
+ print(record._xobject.samples)
237
+ ```
238
+
239
+ The attributes listed in `_xofields` are backed by the same memory as
240
+ `record._xobject`. Array fields are exposed as NumPy or NumPy-like arrays on the
241
+ owning context.
242
+
243
+ ### Strings and References
244
+
245
+ `String` stores a null-terminated variable-length string. `Ref(T)` stores a
246
+ reference to another object of type `T` in the same buffer. `UnionRef` stores a
247
+ reference that can point to one of several declared xobject types.
248
+
249
+ References are useful when multiple objects need to share data without copying
250
+ it. They must refer to objects in the same buffer because the stored value is a
251
+ relative offset.
252
+
253
+ ## The C Programming Model
254
+
255
+ Every xobject type can generate C declarations and accessor functions for its
256
+ buffer layout. This lets kernel code read and write fields without hard-coding
257
+ offsets.
258
+
259
+ ```python
260
+ import xobjects as xo
261
+
262
+ class Point(xo.Struct):
263
+ x = xo.Float64
264
+ y = xo.Float64
265
+
266
+ print(Point._gen_c_api().source)
267
+ ```
268
+
269
+ The generated API includes functions such as:
270
+
271
+ ```c
272
+ double Point_get_x(const Point obj);
273
+ void Point_set_x(Point obj, double value);
274
+ double* Point_getp_x(Point obj);
275
+ ```
276
+
277
+ For array fields, the generated API also includes length, getter, setter, and
278
+ pointer helpers. For references and unions, it includes helpers that recover the
279
+ referenced object and type information.
280
+
281
+ Handwritten C code should use the generated accessors instead of assuming a
282
+ particular byte layout. That keeps the source portable across CPU, CUDA, and
283
+ OpenCL backends and across static or dynamic field layouts.
284
+
285
+ Xobjects provides portability macros through `xobjects/headers/common.h`, for
286
+ example `GPUFUN`, `GPUKERN`, `GPUGLMEM`, and `RESTRICT`.
287
+
288
+ ## Defining Kernels
289
+
290
+ A kernel is a compiled function registered on a context. Its source is C-like
291
+ code and its Python-side signature is described with `xo.Kernel` and `xo.Arg`.
292
+ Xobjects uses the signature to generate the required type API, compile the
293
+ source for the selected backend, and expose the result through `context.kernels`.
294
+
295
+ ```python
296
+ import numpy as np
297
+ import xobjects as xo
298
+
299
+ ctx = xo.ContextCpu()
300
+
301
+ source = r"""
302
+ GPUKERN
303
+ void scale_and_add(const int32_t n,
304
+ const double a,
305
+ GPUGLMEM const double* x,
306
+ GPUGLMEM double* y)
307
+ {
308
+ VECTORIZE_OVER(i, n)
309
+ y[i] = a * x[i] + y[i];
310
+ END_VECTORIZE
311
+ }
312
+ """
313
+
314
+ kernels = {
315
+ "scale_and_add": xo.Kernel(
316
+ args=[
317
+ xo.Arg(xo.Int32, name="n"),
318
+ xo.Arg(xo.Float64, name="a"),
319
+ xo.Arg(xo.Float64, pointer=True, const=True, name="x"),
320
+ xo.Arg(xo.Float64, pointer=True, name="y"),
321
+ ],
322
+ n_threads="n",
323
+ )
324
+ }
325
+
326
+ ctx.add_kernels(
327
+ sources=[source],
328
+ kernels=kernels,
329
+ extra_headers=['#include "xobjects/headers/common.h"'],
330
+ )
331
+
332
+ x = ctx.nparray_to_context_array(np.arange(5, dtype=np.float64))
333
+ y = ctx.nparray_to_context_array(np.ones(5, dtype=np.float64))
334
+
335
+ ctx.kernels.scale_and_add(n=len(x), a=2.0, x=x, y=y)
336
+ print(ctx.nparray_from_context_array(y))
337
+ ```
338
+
339
+ Kernels can also take xobject structs or arrays as arguments:
340
+
341
+ ```python
342
+ import xobjects as xo
343
+
344
+ class Point(xo.Struct):
345
+ x = xo.Float64
346
+ y = xo.Float64
347
+
348
+ source = r"""
349
+ GPUFUN
350
+ double norm2(Point p)
351
+ {
352
+ return Point_get_x(p) * Point_get_x(p)
353
+ + Point_get_y(p) * Point_get_y(p);
354
+ }
355
+ """
356
+
357
+ kernels = {
358
+ "norm2": xo.Kernel(
359
+ args=[xo.Arg(Point, name="p")],
360
+ ret=xo.Arg(xo.Float64),
361
+ )
362
+ }
363
+
364
+ ctx = xo.ContextCpu()
365
+ ctx.add_kernels(
366
+ sources=[source],
367
+ kernels=kernels,
368
+ extra_headers=['#include "xobjects/headers/common.h"'],
369
+ )
370
+
371
+ point = Point(x=3.0, y=4.0, _context=ctx)
372
+ print(ctx.kernels.norm2(p=point))
373
+ ```
374
+
375
+ For reusable classes, kernel descriptions can be attached to a `Struct` or
376
+ `HybridClass` through `_kernels` and compiled with `compile_kernels()`.
377
+
378
+ Loops written with `VECTORIZE_OVER` use the execution policy of the selected
379
+ context. On a serial CPU context they become regular `for` loops. On an OpenMP
380
+ CPU context they become OpenMP parallel loops. On GPU contexts they map to the
381
+ backend thread index.
382
+
383
+ ## Moving and Copying
384
+
385
+ Hybrid objects support moving or copying data across buffers and contexts:
386
+
387
+ ```python
388
+ import xobjects as xo
389
+
390
+ class Item(xo.HybridClass):
391
+ _xofields = {
392
+ "value": xo.Float64,
393
+ }
394
+
395
+ cpu_item = Item(value=1.0, _context=xo.ContextCpu())
396
+
397
+ other_cpu_ctx = xo.ContextCpu()
398
+ other_item = cpu_item.copy(_context=other_cpu_ctx)
399
+ cpu_item.move(_buffer=xo.context_default.new_buffer())
400
+ ```
401
+
402
+ Objects with references have stricter rules because references are buffer-local.
403
+ When using `Ref` or `UnionRef`, keep the referencing object and the referenced
404
+ object in the same buffer.