PyParticles3 0.4.0__py3-none-any.whl

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 (100) hide show
  1. pyparticles/__init__.py +26 -0
  2. pyparticles/__main__.py +7 -0
  3. pyparticles/animation/__init__.py +21 -0
  4. pyparticles/animation/animated_cli.py +53 -0
  5. pyparticles/animation/animated_ogl.py +691 -0
  6. pyparticles/animation/animated_ogl_compat.py +243 -0
  7. pyparticles/animation/animated_scatter.py +94 -0
  8. pyparticles/animation/animation.py +251 -0
  9. pyparticles/animation/test_animation.py +310 -0
  10. pyparticles/demo/__init__.py +33 -0
  11. pyparticles/demo/bubble.py +106 -0
  12. pyparticles/demo/electromagnetic_demo.py +128 -0
  13. pyparticles/demo/electrostatic_demo.py +126 -0
  14. pyparticles/demo/fountain.py +478 -0
  15. pyparticles/demo/gas_lennard_jones.py +87 -0
  16. pyparticles/demo/gravity_clusters.py +73 -0
  17. pyparticles/demo/solar_system.py +222 -0
  18. pyparticles/demo/springs.py +141 -0
  19. pyparticles/demo/springs_constr.py +135 -0
  20. pyparticles/demo/test.py +34 -0
  21. pyparticles/forces/__init__.py +21 -0
  22. pyparticles/forces/const_force.py +140 -0
  23. pyparticles/forces/damping.py +174 -0
  24. pyparticles/forces/drag.py +167 -0
  25. pyparticles/forces/electromagnetic.py +105 -0
  26. pyparticles/forces/electromagnetic_field.py +95 -0
  27. pyparticles/forces/electrostatic.py +72 -0
  28. pyparticles/forces/force.py +75 -0
  29. pyparticles/forces/force_constrained.py +32 -0
  30. pyparticles/forces/fused_const_drag.py +445 -0
  31. pyparticles/forces/gravity.py +345 -0
  32. pyparticles/forces/lennard_jones.py +74 -0
  33. pyparticles/forces/linear_spring.py +86 -0
  34. pyparticles/forces/linear_spring_constrained.py +72 -0
  35. pyparticles/forces/multiple_force.py +134 -0
  36. pyparticles/forces/pseudo_bubble.py +226 -0
  37. pyparticles/forces/van_der_waals_force.py +60 -0
  38. pyparticles/forces/vector_field_force.py +52 -0
  39. pyparticles/geometry/__init__.py +21 -0
  40. pyparticles/geometry/dist.py +24 -0
  41. pyparticles/geometry/intersection.py +62 -0
  42. pyparticles/geometry/transformations.py +387 -0
  43. pyparticles/main/__init__.py +21 -0
  44. pyparticles/main/main.py +466 -0
  45. pyparticles/measures/__init__.py +21 -0
  46. pyparticles/measures/elastic_potential_energy.py +67 -0
  47. pyparticles/measures/gravitational_potential_energy.py +69 -0
  48. pyparticles/measures/kinetic_energy.py +68 -0
  49. pyparticles/measures/mass.py +59 -0
  50. pyparticles/measures/measure.py +156 -0
  51. pyparticles/measures/momentum.py +144 -0
  52. pyparticles/measures/total_energy.py +68 -0
  53. pyparticles/ode/__init__.py +21 -0
  54. pyparticles/ode/euler_solver.py +214 -0
  55. pyparticles/ode/euler_solver_constrained.py +49 -0
  56. pyparticles/ode/leapfrog_solver.py +37 -0
  57. pyparticles/ode/leapfrog_solver_constrained.py +53 -0
  58. pyparticles/ode/midpoint_solver.py +43 -0
  59. pyparticles/ode/midpoint_solver_constrained.py +60 -0
  60. pyparticles/ode/ode_solver.py +134 -0
  61. pyparticles/ode/ode_solver_constrained.py +43 -0
  62. pyparticles/ode/runge_kutta_solver.py +79 -0
  63. pyparticles/ode/runge_kutta_solver_constrained.py +98 -0
  64. pyparticles/ode/sim_time.py +56 -0
  65. pyparticles/ode/stormer_verlet_solver.py +50 -0
  66. pyparticles/ode/stormer_verlet_solver_constrained.py +73 -0
  67. pyparticles/ogl/__init__.py +21 -0
  68. pyparticles/ogl/axis_ogl.py +210 -0
  69. pyparticles/ogl/draw_particles_ogl.py +313 -0
  70. pyparticles/ogl/draw_particles_ogl_compat.py +509 -0
  71. pyparticles/ogl/draw_vector_field.py +221 -0
  72. pyparticles/ogl/opencl_gl_vbo.py +485 -0
  73. pyparticles/ogl/trackball.py +131 -0
  74. pyparticles/ogl/translate_scene.py +87 -0
  75. pyparticles/pset/__init__.py +21 -0
  76. pyparticles/pset/boundary.py +69 -0
  77. pyparticles/pset/cluster.py +28 -0
  78. pyparticles/pset/constrained_force_interactions.py +63 -0
  79. pyparticles/pset/constrained_x.py +158 -0
  80. pyparticles/pset/constraint.py +42 -0
  81. pyparticles/pset/default_boundary.py +43 -0
  82. pyparticles/pset/file_cluster.py +131 -0
  83. pyparticles/pset/logger.py +152 -0
  84. pyparticles/pset/octree.py +451 -0
  85. pyparticles/pset/opencl_context.py +374 -0
  86. pyparticles/pset/particles_set.py +499 -0
  87. pyparticles/pset/periodic_boundary.py +36 -0
  88. pyparticles/pset/rand_cluster.py +188 -0
  89. pyparticles/pset/rebound_boundary.py +68 -0
  90. pyparticles/utils/__init__.py +21 -0
  91. pyparticles/utils/parse_args.py +72 -0
  92. pyparticles/utils/problem_config.py +608 -0
  93. pyparticles/utils/pypart_global.py +122 -0
  94. pyparticles/utils/time_formatter.py +50 -0
  95. pyparticles3-0.4.0.dist-info/METADATA +395 -0
  96. pyparticles3-0.4.0.dist-info/RECORD +100 -0
  97. pyparticles3-0.4.0.dist-info/WHEEL +5 -0
  98. pyparticles3-0.4.0.dist-info/entry_points.txt +3 -0
  99. pyparticles3-0.4.0.dist-info/licenses/LICENSE-gpl-3.0.txt +674 -0
  100. pyparticles3-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,122 @@
1
+ # PyParticles : Particles simulation in python
2
+ # Copyright (C) 2012 Simone Riva
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ """Project-wide version and optional dependency probes."""
18
+
19
+ import zlib
20
+
21
+
22
+ v_major = 0
23
+ v_minor = 4
24
+ v_revision = 0
25
+ v_prerelease = ""
26
+
27
+ _GL_INTEROP_WARNING_EMITTED = False
28
+
29
+
30
+ def py_particle_version(r="s"):
31
+ """Return the PyParticles3 compatibility version.
32
+
33
+ The string form follows the PyPI distribution version. The historical
34
+ tuple form remains a three-integer tuple for compatibility with callers
35
+ that expect ``(major, minor, revision)``.
36
+ """
37
+ if r == "s":
38
+ return "%d.%d.%d%s" % (v_major, v_minor, v_revision, v_prerelease)
39
+ return (v_major, v_minor, v_revision)
40
+
41
+
42
+ def _warn_if_pyopencl_lacks_gl(cl):
43
+ """Emit a one-time explanation when only compute OpenCL is available."""
44
+ global _GL_INTEROP_WARNING_EMITTED
45
+
46
+ if _GL_INTEROP_WARNING_EMITTED:
47
+ return
48
+
49
+ have_gl = getattr(cl, "have_gl", None)
50
+ if have_gl is None:
51
+ return
52
+
53
+ try:
54
+ gl_enabled = bool(have_gl())
55
+ except Exception:
56
+ return
57
+
58
+ if gl_enabled:
59
+ return
60
+
61
+ _GL_INTEROP_WARNING_EMITTED = True
62
+ print("")
63
+ print("WARNING: PyOpenCL was built without OpenGL interoperability (have_gl=False).")
64
+ print("OpenCL compute remains available, but CL/GL rendering will use host")
65
+ print("synchronization and can be much slower for large particle counts.")
66
+ print("For CL/GL interoperability, rebuild PyOpenCL from source with")
67
+ print("PYOPENCL_ENABLE_GL=ON and verify that pyopencl.have_gl() is True.")
68
+ print("")
69
+
70
+
71
+ def test_pyopencl():
72
+ """Return True only when PyOpenCL has at least one usable device."""
73
+ try:
74
+ import pyopencl as cl
75
+ except ImportError:
76
+ return False
77
+
78
+ try:
79
+ usable = any(platform.get_devices() for platform in cl.get_platforms())
80
+ except Exception:
81
+ # Broken/missing ICDs may allow importing pyopencl while still making
82
+ # every OpenCL operation unusable.
83
+ return False
84
+
85
+ if usable:
86
+ _warn_if_pyopencl_lacks_gl(cl)
87
+ return usable
88
+
89
+
90
+ def about():
91
+ mail = zlib.decompress(
92
+ b"x\x9c+\xce\xcc\xcd\xcfK\xd5+*KtH\xcfM\xcc\xcc\xd1K\xce\xcf\x05\x00R\x9c\x07\xba"
93
+ ).decode("utf-8")
94
+
95
+ message = """
96
+
97
+ PyParticles3 is an independent modernization of the original PyParticles
98
+ particle simulation toolbox created by Simone Riva.
99
+
100
+ The project preserves the original educational architecture while adding
101
+ modern Python compatibility, tests, OpenCL acceleration, OpenCL/OpenGL
102
+ interoperability, GPU profiling, and updated documentation.
103
+
104
+ Modern source: https://github.com/jamaj69/pyparticles
105
+ Original source: https://github.com/simon-r/PyParticles
106
+
107
+ Original copyright (C) 2012 Simone Riva, email: %s
108
+
109
+ --------------------------------------------------------------------
110
+
111
+ This program is free software: you can redistribute it and/or modify
112
+ it under the terms of the GNU General Public License as published by
113
+ the Free Software Foundation, either version 3 of the License, or
114
+ (at your option) any later version.
115
+
116
+ This program is distributed in the hope that it will be useful,
117
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
118
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
119
+ GNU General Public License for more details.
120
+ """
121
+
122
+ print(message % mail)
@@ -0,0 +1,50 @@
1
+ # PyParticles : Particles simulation in python
2
+ # Copyright (C) 2012 Simone Riva
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ import time
19
+
20
+ class MyTimeFormatter( object ):
21
+
22
+ def __init__(self):
23
+ pass
24
+
25
+
26
+ def to_str( self , t ):
27
+
28
+ tf = [ "%4dy " , "%3dd " , "%02dh " , "%02dm " , "%02ds " , "%07.3fms " ]
29
+
30
+ days_y = 365.256363004
31
+ sec_y = days_y * 3600 * 24
32
+
33
+ years = int( t / sec_y )
34
+ days = int( t / (3600*24) - years*days_y )
35
+ hr = int( t / 3600 - days*24 - days_y*years*24 )
36
+ minu = int( t / 60 - hr*60 - days*(24*60) - days_y*years*24*60 )
37
+ sec = int( t - minu*60 - hr*3600 - days*(24*3600) - days_y*years*24*60*60 )
38
+ msec = float( 1000 * ( t - int( t ) ) )
39
+
40
+ res = ""
41
+
42
+ i = 0
43
+ f = False
44
+ for tt in list( [ years , days , hr , minu , sec , msec ] ):
45
+ if tt > 0 or f :
46
+ res = res + tf[i] % tt
47
+ f = True
48
+ i+=1
49
+
50
+ return res
@@ -0,0 +1,395 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyParticles3
3
+ Version: 0.4.0
4
+ Summary: Modern educational particle simulation toolbox with OpenCL/OpenGL acceleration
5
+ Author: Simone Riva
6
+ Maintainer: jamaj69
7
+ License-Expression: GPL-3.0-or-later
8
+ Project-URL: Homepage, https://github.com/jamaj69/pyparticles
9
+ Project-URL: Source, https://github.com/jamaj69/pyparticles
10
+ Project-URL: Documentation, https://github.com/jamaj69/pyparticles#readme
11
+ Project-URL: Issues, https://github.com/jamaj69/pyparticles/issues
12
+ Project-URL: Original Project, https://github.com/simon-r/PyParticles
13
+ Keywords: particles,simulation,physics,opencl,opengl,gpu,scientific-computing,education
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Education
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Topic :: Scientific/Engineering :: Physics
18
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Operating System :: POSIX :: Linux
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE-gpl-3.0.txt
27
+ Requires-Dist: numpy>=2.0
28
+ Requires-Dist: scipy>=1.14
29
+ Requires-Dist: PyOpenGL>=3.1.7
30
+ Requires-Dist: matplotlib>=3.8
31
+ Provides-Extra: opencl
32
+ Requires-Dist: pyopencl>=2026.1; extra == "opencl"
33
+ Provides-Extra: dev
34
+ Requires-Dist: build>=1.2; extra == "dev"
35
+ Requires-Dist: twine>=5; extra == "dev"
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs>=1.6; extra == "docs"
38
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
39
+ Requires-Dist: pymdown-extensions>=10; extra == "docs"
40
+ Dynamic: license-file
41
+
42
+ # PyParticles3
43
+
44
+ **PyParticles3** is an independent modernization and continuation of Simone Riva's original **PyParticles** project.
45
+
46
+ The goal is to preserve the original project's unusually clear, educational architecture while updating it for modern Python, NumPy, SciPy, PyOpenGL and PyOpenCL environments. PyParticles3 is also a practical study project for GPU particle simulation, OpenCL acceleration and OpenCL/OpenGL interoperability.
47
+
48
+ > PyParticles3 is not presented as an official release endorsed by Simone Riva. Original copyright notices and the GPL-3.0-or-later license are preserved.
49
+
50
+ ## Highlights
51
+
52
+ - simple `ParticlesSet -> Force -> Solver -> Animation/Renderer` architecture;
53
+ - Euler, Leapfrog, Runge-Kutta, Midpoint and Stormer-Verlet style integrators;
54
+ - gravity, springs, constant force, drag, damping, Lennard-Jones, electrostatic and electromagnetic models;
55
+ - constrained particles and constrained force interactions;
56
+ - OpenGL interactive visualization;
57
+ - optional PyOpenCL acceleration;
58
+ - persistent OpenCL buffers to avoid unnecessary PCIe transfers;
59
+ - fused OpenCL integration paths;
60
+ - OpenCL/OpenGL shared VBO rendering;
61
+ - double-buffered CL/GL synchronization with GL fences;
62
+ - asynchronous OpenGL GPU timer queries;
63
+ - an optimized `fountain` example used as a GPU performance case study.
64
+
65
+ ## Installation
66
+
67
+ The stable release line is **PyParticles3 0.4.0**. The Python import namespace remains `pyparticles`.
68
+
69
+ PyParticles3 requires Python 3.11 or newer.
70
+
71
+ ### 1. Standard installation
72
+
73
+ Install PyParticles3 from PyPI:
74
+
75
+ ```bash
76
+ python -m pip install --upgrade pip
77
+ python -m pip install 'PyParticles3==0.4.0'
78
+ ```
79
+
80
+ Verify the installation:
81
+
82
+ ```bash
83
+ pyparticles3 --version
84
+ python -m pyparticles --version
85
+ ```
86
+
87
+ Both commands should report:
88
+
89
+ ```text
90
+ 0.4.0
91
+ ```
92
+
93
+ The historical console command remains available for compatibility:
94
+
95
+ ```bash
96
+ pyparticles_app --version
97
+ ```
98
+
99
+ ### 2. Installation with OpenCL compute support
100
+
101
+ Install the optional OpenCL dependency set with:
102
+
103
+ ```bash
104
+ python -m pip install 'PyParticles3[opencl]==0.4.0'
105
+ ```
106
+
107
+ This installs PyOpenCL, but it does **not** install a system OpenCL driver/ICD. A working NVIDIA, Intel, AMD, PoCL or other OpenCL runtime must already be installed on the operating system.
108
+
109
+ List the OpenCL platforms and devices visible to PyOpenCL:
110
+
111
+ ```bash
112
+ python - <<'PY'
113
+ import pyopencl as cl
114
+
115
+ for pi, platform in enumerate(cl.get_platforms()):
116
+ print(f"Platform {pi}: {platform.name}")
117
+ for di, device in enumerate(platform.get_devices()):
118
+ print(f" Device {di}: {device.name}")
119
+ PY
120
+ ```
121
+
122
+ PyParticles3 follows PyOpenCL's `PYOPENCL_CTX` selector. For example:
123
+
124
+ ```bash
125
+ PYOPENCL_CTX=0:0 pyparticles3 --demo fountain
126
+ PYOPENCL_CTX=1:0 pyparticles3 --demo fountain
127
+ ```
128
+
129
+ An explicitly selected compute device is never silently replaced by a different OpenCL device merely to obtain OpenCL/OpenGL sharing.
130
+
131
+ ### 3. Check whether PyOpenCL has OpenGL interoperability
132
+
133
+ The PyPI PyOpenCL wheel can provide fully working OpenCL compute while still being built **without** OpenGL interoperability. Check the installed build explicitly:
134
+
135
+ ```bash
136
+ python - <<'PY'
137
+ import pyopencl as cl
138
+
139
+ print("PyOpenCL :", cl.VERSION_TEXT)
140
+ print("Module :", cl.__file__)
141
+ print("have_gl :", cl.have_gl())
142
+ PY
143
+ ```
144
+
145
+ For ordinary OpenCL compute, either value of `have_gl()` is acceptable.
146
+
147
+ For the high-performance OpenCL/OpenGL shared-buffer path used by the `fountain` demo, PyOpenCL itself must report:
148
+
149
+ ```text
150
+ have_gl : True
151
+ ```
152
+
153
+ If it reports:
154
+
155
+ ```text
156
+ have_gl : False
157
+ ```
158
+
159
+ OpenCL compute still works, but PyParticles3 cannot create PyOpenCL `GLBuffer` objects. Rendering then uses host synchronization and can be dramatically slower for large particle counts.
160
+
161
+ ### 4. Build PyOpenCL from source with `have_gl=True`
162
+
163
+ PyOpenCL's source-build documentation requires the build option `PYOPENCL_ENABLE_GL=ON` to enable OpenGL interoperability.
164
+
165
+ #### Debian 12 / Debian-family build prerequisites
166
+
167
+ A typical Debian installation can provide the native build dependencies with:
168
+
169
+ ```bash
170
+ sudo apt update
171
+ sudo apt install \
172
+ build-essential \
173
+ python3-dev \
174
+ cmake \
175
+ ninja-build \
176
+ pkg-config \
177
+ ocl-icd-opencl-dev \
178
+ libgl-dev \
179
+ freeglut3-dev
180
+ ```
181
+
182
+ `ocl-icd-opencl-dev` supplies the OpenCL development headers and loader needed to compile against the system OpenCL installation. Your actual OpenCL implementation/ICD, such as the NVIDIA or Intel runtime, remains a separate system component.
183
+
184
+ If Python comes from pyenv or another custom Python installation, make sure that installation includes its matching Python headers; the system `python3-dev` package applies to Debian's system Python.
185
+
186
+ #### Rebuild PyOpenCL
187
+
188
+ Inside the same virtual environment in which PyParticles3 is installed:
189
+
190
+ ```bash
191
+ python -m pip uninstall -y pyopencl
192
+
193
+ PYOPENCL_ENABLE_GL=ON \
194
+ python -m pip install \
195
+ --no-binary=pyopencl \
196
+ --no-cache-dir \
197
+ -v \
198
+ 'pyopencl==2026.1.4'
199
+ ```
200
+
201
+ `--no-binary=pyopencl` is important: it forces a source build instead of reinstalling the precompiled wheel.
202
+
203
+ The `0.4.0` release line was qualified with PyOpenCL `2026.1.4`. Newer compatible PyOpenCL releases can also be built from source, but should be tested before being used as a release-validation baseline.
204
+
205
+ #### Verify the resulting build
206
+
207
+ Do not assume that a successful compilation enabled GL support. Require it explicitly:
208
+
209
+ ```bash
210
+ python - <<'PY'
211
+ import pyopencl as cl
212
+
213
+ print("PyOpenCL :", cl.VERSION_TEXT)
214
+ print("Module :", cl.__file__)
215
+ print("have_gl :", cl.have_gl())
216
+
217
+ assert cl.have_gl(), "PyOpenCL was built without OpenGL interoperability"
218
+ PY
219
+ ```
220
+
221
+ The final line must be:
222
+
223
+ ```text
224
+ have_gl : True
225
+ ```
226
+
227
+ #### Verify the PyParticles3 CL/GL path
228
+
229
+ Select an OpenCL GPU that can share the active OpenGL context and run:
230
+
231
+ ```bash
232
+ PYOPENCL_CTX=0:0 pyparticles3 --demo fountain
233
+ ```
234
+
235
+ A successful shared-buffer path reports messages similar to:
236
+
237
+ ```text
238
+ OpenCL/OpenGL interop enabled: positions render without host copies
239
+ CL/GL sync: double-buffered VBOs with per-buffer GL fences
240
+ CL/GL position path: X -> VBO device copy (stable)
241
+ Interop device: NVIDIA GeForce ...
242
+ ```
243
+
244
+ `pyopencl.have_gl() == True` means that the **PyOpenCL build** contains GL interoperability support. It does not guarantee that every OpenCL device can share the current OpenGL context. The selected device must also support `cl_khr_gl_sharing` and be compatible with the active GL context.
245
+
246
+ For example, on a mixed NVIDIA-GPU/Intel-CPU system, an Intel CPU OpenCL device may run all simulation kernels correctly but not advertise `cl_khr_gl_sharing`. PyParticles3 then keeps the Intel device selected and explicitly falls back to host-synchronized rendering instead of moving the computation to NVIDIA.
247
+
248
+ ### 5. System OpenGL requirements
249
+
250
+ Interactive rendering requires a working OpenGL implementation and FreeGLUT. These are operating-system dependencies and are not installed by pip.
251
+
252
+ On Debian-family systems, the development packages used above include the common OpenGL/FreeGLUT headers. The graphics driver must still provide a working OpenGL runtime.
253
+
254
+ ### 6. Install from the Git repository
255
+
256
+ For development or testing the current repository state:
257
+
258
+ ```bash
259
+ git clone https://github.com/jamaj69/pyparticles.git
260
+ cd pyparticles
261
+
262
+ python -m venv .venv
263
+ source .venv/bin/activate
264
+ python -m pip install --upgrade pip
265
+ python -m pip install -e '.[dev]'
266
+ ```
267
+
268
+ For development with OpenCL support:
269
+
270
+ ```bash
271
+ python -m pip install -e '.[dev,opencl]'
272
+ ```
273
+
274
+ If CL/GL interoperability is required, rebuild PyOpenCL with `PYOPENCL_ENABLE_GL=ON` after installing the editable package, using the procedure above.
275
+
276
+ ## Current import namespace
277
+
278
+ The PyParticles3 0.4.x release line intentionally keeps the historical Python import namespace:
279
+
280
+ ```python
281
+ import pyparticles
282
+ ```
283
+
284
+ This avoids mixing a package-wide namespace migration with the first modernized stable release. A future release may introduce a dedicated `pyparticles3` namespace after a controlled compatibility migration.
285
+
286
+ ## Command line
287
+
288
+ The modern package exposes:
289
+
290
+ ```bash
291
+ pyparticles3 --help
292
+ pyparticles3 --version
293
+ ```
294
+
295
+ The historical command is also kept as a compatibility entry point:
296
+
297
+ ```bash
298
+ pyparticles_app --help
299
+ ```
300
+
301
+ Examples:
302
+
303
+ ```bash
304
+ pyparticles3 --demo springs
305
+ pyparticles3 --demo solar_system
306
+ pyparticles3 --demo bubble
307
+ pyparticles3 --demo gas_lj
308
+ pyparticles3 --demo elmag_field
309
+ pyparticles3 --demo galaxy
310
+ pyparticles3 --demo fountain
311
+ ```
312
+
313
+ ## Architecture
314
+
315
+ ```text
316
+ ParticlesSet
317
+ |
318
+ +--> Force / MultipleForce
319
+ | |
320
+ | v
321
+ +----> ODE Solver
322
+ |
323
+ v
324
+ Animation
325
+ |
326
+ v
327
+ Renderer
328
+ ```
329
+
330
+ The accelerated paths preserve these conceptual roles rather than replacing the whole program with an opaque GPU pipeline.
331
+
332
+ ## OpenCL/OpenGL fountain path
333
+
334
+ The modern `fountain` demo can keep simulation state resident on the GPU and render from shared OpenGL buffers.
335
+
336
+ The stable default shared path copies positions from the canonical OpenCL position buffer into a shared OpenGL VBO entirely on the device. The code also contains an optional experimental fused render-mirror path that can write the shared render VBO directly from the integration kernel.
337
+
338
+ Profiling can be enabled with:
339
+
340
+ ```bash
341
+ PYPARTICLES_PROFILE_CLGL=1 \
342
+ PYPARTICLES_PROFILE_FRAMES=1000 \
343
+ PYPARTICLES_PROFILE_WARMUP=200 \
344
+ pyparticles3 --demo fountain
345
+ ```
346
+
347
+ The experimental fused render mirror is selected with:
348
+
349
+ ```bash
350
+ PYPARTICLES_CLGL_FUSED_MIRROR=1 \
351
+ pyparticles3 --demo fountain
352
+ ```
353
+
354
+ The final `0.4.0` release is based on the validated `0.4.0rc2` code path. The release-candidate baseline on a GeForce GTX 1060 6 GB with 2,000,000 fountain particles produced roughly 278-296 FPS, with the fused physics kernel around 0.760 ms and the device-side X-to-VBO copy around 0.324 ms. Treat these numbers as a hardware-specific regression baseline, not as a general performance guarantee.
355
+
356
+ ## Development
357
+
358
+ ```bash
359
+ git clone https://github.com/jamaj69/pyparticles.git
360
+ cd pyparticles
361
+
362
+ python -m venv .venv
363
+ source .venv/bin/activate
364
+ python -m pip install -U pip
365
+ python -m pip install -e '.[dev]'
366
+
367
+ python -m compileall -q pyparticles tests
368
+ python -W default -m unittest discover -v -s tests
369
+ ```
370
+
371
+ Build the PyPI artifacts with:
372
+
373
+ ```bash
374
+ python -m pip install -U build twine
375
+ rm -rf build dist *.egg-info
376
+ python -m build
377
+ python -m twine check dist/*
378
+ ```
379
+
380
+ ## Project links
381
+
382
+ - Source: https://github.com/jamaj69/pyparticles
383
+ - Issues: https://github.com/jamaj69/pyparticles/issues
384
+ - Original project: https://github.com/simon-r/PyParticles
385
+ - PyOpenCL installation/build documentation: https://documen.tician.de/pyopencl/misc.html
386
+
387
+ When releases are published through PyPI Trusted Publishing from this GitHub repository, PyPI can verify the GitHub project links carried in the distribution metadata.
388
+
389
+ ## Origin and attribution
390
+
391
+ PyParticles was created by **Simone Riva** in 2012. PyParticles3 is an independent modernization built from that GPL-licensed codebase. The modernization focuses on Python 3 compatibility, modern scientific Python libraries, testing, GPU acceleration, CL/GL interoperability and documentation while preserving the original educational structure.
392
+
393
+ ## License
394
+
395
+ GPL-3.0-or-later. See `LICENSE-gpl-3.0.txt`.
@@ -0,0 +1,100 @@
1
+ pyparticles/__init__.py,sha256=Mqc8FcYcmqLoqBuFBHNM_hBXQVfeaTpzOaJdmcGRf2s,907
2
+ pyparticles/__main__.py,sha256=DimbxF9a6U_jTcTVs3a4Vq0JtN3v1yizDD3fQCieG3c,161
3
+ pyparticles/animation/__init__.py,sha256=YWGJrPjamB49wRPTqdjfo6-T1lUvlLfshIqUGsPNh4Q,857
4
+ pyparticles/animation/animated_cli.py,sha256=kUlNFN7X2UpmPUOdTZtOlscglcKWDUzVVBH7jyLcBYo,1635
5
+ pyparticles/animation/animated_ogl.py,sha256=nZwq9peYMHakqM0ZAXJbdRCBjR3YQaNYs7pYhPvr96w,20897
6
+ pyparticles/animation/animated_ogl_compat.py,sha256=KQNhmiYYCULXryse3gotOOBOJAx-D4l-vfJ-bv5hMfw,8482
7
+ pyparticles/animation/animated_scatter.py,sha256=xLCOUit0zzT99CZf6pzc6iTe9kRG615-ecYS0Duikow,2961
8
+ pyparticles/animation/animation.py,sha256=axKzZ-9xDDntIY9FG4SBHSXJHIPA0I6HAJqHcO7JbNs,7025
9
+ pyparticles/animation/test_animation.py,sha256=TRbb7wA91Z_VBNFxN-vX5_ovkW8UrcNUxVmBG5_DeFE,9773
10
+ pyparticles/demo/__init__.py,sha256=6X6qEyq3c85ivWMm7vJYWHAGCzI3QSm3tGCd70rujq8,1367
11
+ pyparticles/demo/bubble.py,sha256=J-nzKma90z_ytEPQ0x0Dh9gc9vM8jt4koFSx_GFgccw,2983
12
+ pyparticles/demo/electromagnetic_demo.py,sha256=PmjE1VOXqBNSO6pLIFsu8kWEennCvDPVtWprkumopjE,3932
13
+ pyparticles/demo/electrostatic_demo.py,sha256=fsUBVuVxa84Unh64ptaTomycnz-kbcV0AO_k074cToo,3591
14
+ pyparticles/demo/fountain.py,sha256=PkFya7SRERu7BqM4OC9CLuayV_hUx0xxklFGQ3DBpfY,19268
15
+ pyparticles/demo/gas_lennard_jones.py,sha256=ptFopN54bGSfrrSmcD9OcvdpE58fn3Mu5WQSGimL294,2531
16
+ pyparticles/demo/gravity_clusters.py,sha256=qOApDKIwLsmiotbFGOdsSK_UrIIC7HMUruIhgOb_dgM,2080
17
+ pyparticles/demo/solar_system.py,sha256=H-uxt40m8u_J1qK9aKvIwdcBT1T-CI0IZrXJQLHpSTw,7086
18
+ pyparticles/demo/springs.py,sha256=VthvlgVlX_LAH_Ix-1t5WbCtJfJeoI2q6IupzDTP2dI,3840
19
+ pyparticles/demo/springs_constr.py,sha256=VKl8FCKQHEHqMjiN7RJfGUNjflVwziwz6fHC5PnOxaI,4004
20
+ pyparticles/demo/test.py,sha256=eJgVFAfrik4YDp0LXgxiY52eCp0qSN93G7uwV0BP2io,1097
21
+ pyparticles/forces/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
22
+ pyparticles/forces/const_force.py,sha256=jXw3iszRhG6fo6OJrUCcSO0eEaZ-HOiVV_HJK6N88kU,3948
23
+ pyparticles/forces/damping.py,sha256=jIwWqvlNTYJN-mvXqjE7FFsRicl2GYNV57Fk4rEyrGs,5007
24
+ pyparticles/forces/drag.py,sha256=clZ3X9tHn1z2n8O_BDdoTbV5uyLomR3jt0Y9iFhh7Hg,4730
25
+ pyparticles/forces/electromagnetic.py,sha256=gV3_t7TwWqaoqH_j8nFr2rnUm4VS77VT5f-e8MGyTU0,3308
26
+ pyparticles/forces/electromagnetic_field.py,sha256=2h0Nkoi96AYPXm6ijQquOKjL9ZQE5xXtI04QpnAgC6Y,2651
27
+ pyparticles/forces/electrostatic.py,sha256=nt6DIH1pFr7cx7QJyuQkPAIoOdyTkhI51l5AbU8uVN8,2298
28
+ pyparticles/forces/force.py,sha256=9KiF8mXs_fcNhI3GdNHZLmWWripJEZ4FwHLsGnSTBm0,2710
29
+ pyparticles/forces/force_constrained.py,sha256=pRm1O4LUgiYOuMiNpdKOAF0SYmOh-6LCQEqS6IrSBfs,1185
30
+ pyparticles/forces/fused_const_drag.py,sha256=mtG6YHJP8BCZiCJaMRr-RoJbCGdP_p9isY5ABXY--E0,14692
31
+ pyparticles/forces/gravity.py,sha256=oJBljaDvcHpjag_bm4fHsPTCfxw3raKekUgA4ttsXCc,10487
32
+ pyparticles/forces/lennard_jones.py,sha256=54n1ii1R12qgdpFqThdOPDAecNkbuJWcj4y07FINk7M,2210
33
+ pyparticles/forces/linear_spring.py,sha256=L6VAu251z_BV0-AKX-P-rGpZ33E-kJ_Jv5kKRIHgxYU,2392
34
+ pyparticles/forces/linear_spring_constrained.py,sha256=TDvHHypK3WjDucNfNaidtCLLwYi0GGJLhz35AscrPaw,2172
35
+ pyparticles/forces/multiple_force.py,sha256=KvROEsLMq6BMlH5A9qRG5Z5YPCZnUe19sx7414eB6gw,4500
36
+ pyparticles/forces/pseudo_bubble.py,sha256=NblMuNammFJ9lVOgC11FZrYBLlgtkHlxu0fAt_BF2xo,6400
37
+ pyparticles/forces/van_der_waals_force.py,sha256=8GqaCT10BRq6z3ISsrx7DiCets8Lu1Q4zTm-m45IcdE,1705
38
+ pyparticles/forces/vector_field_force.py,sha256=S-Qps149mRaT_cPtljDg1uuynaHz6dbEMvBBZIsZgfI,1607
39
+ pyparticles/geometry/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
40
+ pyparticles/geometry/dist.py,sha256=q842yPnjeBQkDNgHhNZYjCZKc_NzS2eHM4grSPFcfR0,876
41
+ pyparticles/geometry/intersection.py,sha256=un1gI4SnPF9IeBI0Kh9iO8QgWYOTP-08Wf93Qy_kglk,1932
42
+ pyparticles/geometry/transformations.py,sha256=esfLTNC3I1AfZOrz5KF-2mvOIRy91z2MxiGUGcco2Kc,11728
43
+ pyparticles/main/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
44
+ pyparticles/main/main.py,sha256=kGnRj9e_RbstQKBF51nyM3LWifnzLOFnE4lJ0V9hN54,11817
45
+ pyparticles/measures/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
46
+ pyparticles/measures/elastic_potential_energy.py,sha256=msISBKcyfdbuGOkcnClUX97fwChQoVRTBa8L4CdUSnw,2023
47
+ pyparticles/measures/gravitational_potential_energy.py,sha256=MXxoOhrkpC5_NZhC6BKPn7ZUKHPKB2Lp5gQVjVTLt9I,2100
48
+ pyparticles/measures/kinetic_energy.py,sha256=SE9rwyOoTef9Hn2YgqHe7yeGzT5Npyg1pt4iNMZFyts,1983
49
+ pyparticles/measures/mass.py,sha256=sqW2WtIGw5sSRWj3ZgwGr0Fb5GJm1wwH0g4LMB7O58c,1672
50
+ pyparticles/measures/measure.py,sha256=QFJ_PuaRK4vmVMdO_1o9C0IErh7BTnyLgg7UNei_DnQ,5202
51
+ pyparticles/measures/momentum.py,sha256=jQTGa1wWiQ5rH_3luXD9jhYGqvVTj4CKx6auGf2o2Uc,4267
52
+ pyparticles/measures/total_energy.py,sha256=XKv2_gSwgWpcAEWxek1RXV6bibpKMz0yxPDZLG2i3CY,2045
53
+ pyparticles/ode/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
54
+ pyparticles/ode/euler_solver.py,sha256=CK2sxgiTRRlYxF_59L3dKclYJFFYx_ujM-JHKPbhqYA,7208
55
+ pyparticles/ode/euler_solver_constrained.py,sha256=tD8mffDHMEAXCQdPKQUEH0lCKwPlRkbVeC-zW2PEw9A,2034
56
+ pyparticles/ode/leapfrog_solver.py,sha256=B11_90B0fiwk74yaICMIgEXzMKaieCPHY_ejDEhFQBc,1350
57
+ pyparticles/ode/leapfrog_solver_constrained.py,sha256=C2pg4yoK-Rm71RbSRiLIj3HpbpkxHEBLxh6dBMojmtQ,2312
58
+ pyparticles/ode/midpoint_solver.py,sha256=3DTjWVWrf887x_friEKFd67w0vv1FCfEiOU5U2yzy5c,1544
59
+ pyparticles/ode/midpoint_solver_constrained.py,sha256=ry5P4pJdGmI2jM3-0wRAcAccgU6ZijCfzcLWxdlXEn0,2521
60
+ pyparticles/ode/ode_solver.py,sha256=7xchJu3-iykDUs2ARaBQd9sCAr37aan8sMbPqYc91t8,4085
61
+ pyparticles/ode/ode_solver_constrained.py,sha256=E-iV40jp1SPOfYYIgdjL1N60XujOlGDrsqXEoVxTZw4,1550
62
+ pyparticles/ode/runge_kutta_solver.py,sha256=MzjA_igEg2BeRVfgap44yOC4qPjxoWNKuXFPOoawLdk,2842
63
+ pyparticles/ode/runge_kutta_solver_constrained.py,sha256=Ikd8bBnCkyFtgEOe4TQoX3CCIUnMEY1mnmYtRB7sELg,4171
64
+ pyparticles/ode/sim_time.py,sha256=7ed5q-keQHOylD01SzwONG7HcboUbhqYIJXFtfP6grI,1710
65
+ pyparticles/ode/stormer_verlet_solver.py,sha256=RLLR7K93xNN6m7aeN46VNoIlrrwq4jcjWExQ7IVrkJk,1960
66
+ pyparticles/ode/stormer_verlet_solver_constrained.py,sha256=99Kgt4Q8iszgFyKF4uM7lAk1pNslpoIS_gGPC6gb1hI,3051
67
+ pyparticles/ogl/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
68
+ pyparticles/ogl/axis_ogl.py,sha256=uzE1ipA8_W7dyNvFrfkSkioXlcEA33nSkF8gDsC3n_k,6440
69
+ pyparticles/ogl/draw_particles_ogl.py,sha256=DmSh9PQyUPtDcFUxDgDnHtfhTHbDrm1DYT7fbc6Mhp8,9974
70
+ pyparticles/ogl/draw_particles_ogl_compat.py,sha256=IQb8h9g_ggoNgPk-0bZ48WxMU1v6eVu-nzHLHs1DC3Y,17486
71
+ pyparticles/ogl/draw_vector_field.py,sha256=nS00OXtc1UWzGishL6NaAtn-XAokpf79tdA4nrSobw8,6765
72
+ pyparticles/ogl/opencl_gl_vbo.py,sha256=9Ad7-OXpHjmKTYOjn7AcpHNO88QyWdJ4Sn7xzn9A3XE,17276
73
+ pyparticles/ogl/trackball.py,sha256=N50FiUXBmzoJq-pHP1Ld7g7kCb6kpb8UOHKL5epzNNI,4249
74
+ pyparticles/ogl/translate_scene.py,sha256=MMhNAJD9I9pCunN8-6HsYU8DzniiG6xglhSnPW2zO_4,2440
75
+ pyparticles/pset/__init__.py,sha256=SfGt0zuyycRf9l-_fov-zBtjfdynjlwFTmnT1KgAzQk,858
76
+ pyparticles/pset/boundary.py,sha256=BRCnoVTG41AlO3a7qC90JGEejCumW0cXJDVmUg4Qajk,2134
77
+ pyparticles/pset/cluster.py,sha256=QtALI9BJPwVGHmWU9lPCvyAVjQoBvTxcbqHG9YvSKDM,914
78
+ pyparticles/pset/constrained_force_interactions.py,sha256=PGQMVfX5YNBsXWPVALSsX8F9sZ3hs3VHFhlg1Am2lqw,1961
79
+ pyparticles/pset/constrained_x.py,sha256=5J8hqnRw7If-vm4bbW0g1b5PxT4AyrMuy_DNIAnpSJE,5381
80
+ pyparticles/pset/constraint.py,sha256=dFDxswFsvd0RehC7jO8f_s_aGxp8fEJuvqbupyAXLKc,1128
81
+ pyparticles/pset/default_boundary.py,sha256=s77GDU0_2GyvyZaCgCKotmBED6gwMutclggvHPWYsBE,1441
82
+ pyparticles/pset/file_cluster.py,sha256=sGitftkajVWM5AW--cAYPOEd8NsIksvYWVuyqTO-8Pk,3421
83
+ pyparticles/pset/logger.py,sha256=HkPSKI0jEr-UwHLeyLXTE0EEXXztno5bZolk4Wr-5fg,4707
84
+ pyparticles/pset/octree.py,sha256=G1KMPQTjCmZyR1RJ0IZn_bKpw2cvdodxxqvKjJlLk7k,14985
85
+ pyparticles/pset/opencl_context.py,sha256=TQ3nsJotpOHdCxiY6-VQ2LQ5Cn75epB3HLCCr7lYXGs,13270
86
+ pyparticles/pset/particles_set.py,sha256=CMvPYHXkcmPGWrSLOWEz3qi68L7LK5fZte6cvz3wBd8,16543
87
+ pyparticles/pset/periodic_boundary.py,sha256=02QGzAFZPOfbSPQUCWliftAlcjr-GgmaXibWHfL-kfw,1273
88
+ pyparticles/pset/rand_cluster.py,sha256=a3PQ497wen10d5YPPCGlV86Uxyb15W-pWc_ER3D5d6o,5299
89
+ pyparticles/pset/rebound_boundary.py,sha256=VjVXPpsZ--z2rIWJ4fD7JeTwph8schrbTQjdQpVTDH4,2087
90
+ pyparticles/utils/__init__.py,sha256=YWGJrPjamB49wRPTqdjfo6-T1lUvlLfshIqUGsPNh4Q,857
91
+ pyparticles/utils/parse_args.py,sha256=Qaz7z6G5jFO5KaVkMKnN_WcVyDVMol2HoJTuVuRg8q4,2273
92
+ pyparticles/utils/problem_config.py,sha256=6FYatMR2gWq8KS9Amk3cDCOTMxyUXCK3zkLsXHG_muU,23753
93
+ pyparticles/utils/pypart_global.py,sha256=G8XmaGta6lhFFfvH1UNAaHCAmeCwakBD4CM9o6-q4No,4018
94
+ pyparticles/utils/time_formatter.py,sha256=OVOCP2eTfAIlz1XrV3yPelXApI6JmV_Qsr2i5X9HJ38,1660
95
+ pyparticles3-0.4.0.dist-info/licenses/LICENSE-gpl-3.0.txt,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
96
+ pyparticles3-0.4.0.dist-info/METADATA,sha256=lv0Ayx5URPWdnBF124awGS9NzTcjZ6v6Ok7776EQDiM,12960
97
+ pyparticles3-0.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
98
+ pyparticles3-0.4.0.dist-info/entry_points.txt,sha256=OTWMifSShnvWdMBY6Sjg6kbHDSSBFCfurheDa8eV1sg,105
99
+ pyparticles3-0.4.0.dist-info/top_level.txt,sha256=bsS4msJ7XYbilhsrlVsXGEdg1tHKp3tBlt6myUY3k2A,12
100
+ pyparticles3-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ pyparticles3 = pyparticles.main.main:main
3
+ pyparticles_app = pyparticles.main.main:main