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,32 @@
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
+ import numpy as np
18
+
19
+ import pyparticles.forces.force as fr
20
+
21
+ class ForceConstrained( fr.Force ) :
22
+ def __init__( self , size , dim , m=None , Conts=1.0 , f_inter=None ):
23
+ self.__f_inter = f_inter
24
+
25
+
26
+ def get_force_interactions( self ):
27
+ return self.__f_inter
28
+
29
+ def set_force_interactions( self , fi ):
30
+ self.__f_inter = fi
31
+
32
+ force_interactions = property( get_force_interactions , set_force_interactions )
@@ -0,0 +1,445 @@
1
+ # PyParticles : Particles simulation in python
2
+ # Copyright (C) 2012 Simone Riva
3
+ #
4
+ # Modern fused OpenCL force/integration helper.
5
+
6
+ import numpy as np
7
+
8
+ import pyparticles.forces.force as fr
9
+ import pyparticles.pset.opencl_context as occ
10
+
11
+ try:
12
+ import pyopencl as cl
13
+ except ImportError:
14
+ cl = None
15
+
16
+
17
+ class FusedConstDragOCL(fr.Force):
18
+ """Constant acceleration plus quadratic drag with a fused Euler step.
19
+
20
+ ``fountain_bounds`` optionally enables the fountain's reset boundary in
21
+ the same kernel launch. The reset follows the original demo's probability
22
+ distributions but uses a small deterministic device-side hash PRNG, so no
23
+ boundary detection or random state needs to cross PCIe.
24
+
25
+ A fountain solver may optionally set a one-shot render target. In that
26
+ mode a dedicated kernel writes the final positions both to canonical ``X``
27
+ and to the supplied OpenCL buffer in the same pass. This is used by the
28
+ experimental CL/GL path to eliminate a separate X -> VBO device copy.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ size,
34
+ dim=3,
35
+ m=None,
36
+ u_force=(0.0, 0.0, 0.0),
37
+ drag_const=1.0,
38
+ ocl_context=None,
39
+ fountain_bounds=None,
40
+ ):
41
+ if cl is None:
42
+ raise RuntimeError("PyOpenCL is required for FusedConstDragOCL")
43
+ if int(dim) != 3:
44
+ raise ValueError("FusedConstDragOCL currently supports only 3 dimensions")
45
+
46
+ self.__size = int(size)
47
+ self.__dim = int(dim)
48
+ self.__occ = ocl_context or occ.OpenCLcontext(
49
+ size,
50
+ dim,
51
+ occ.OCLC_X | occ.OCLC_V | occ.OCLC_A | occ.OCLC_M,
52
+ )
53
+ self.__dtype = self.__occ.dtype
54
+ self.__UF = np.asarray(u_force, dtype=self.__dtype).reshape(3)
55
+ self.__K = self.__dtype(drag_const)
56
+ self.__A = np.zeros((size, dim), dtype=self.__dtype)
57
+ self.__M = np.zeros((size, 1), dtype=self.__dtype)
58
+ self.__fountain_bounds = None
59
+ self.__last_step_event = None
60
+ self.__render_target = None
61
+ self.__render_wait_for = None
62
+ if fountain_bounds is not None:
63
+ bounds = np.asarray(fountain_bounds, dtype=self.__dtype).reshape(-1)
64
+ if bounds.size != 6:
65
+ raise ValueError("fountain_bounds must contain 6 values")
66
+ self.__fountain_bounds = bounds
67
+
68
+ self.__build_program()
69
+ if m is not None:
70
+ self.set_masses(m)
71
+
72
+ def __build_program(self):
73
+ source = r"""
74
+ inline float3 const_drag_accel(
75
+ float3 v,
76
+ float mass,
77
+ float3 constant_a,
78
+ float K)
79
+ {
80
+ float speed = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
81
+ float scale = (-0.5f * K * speed) / mass;
82
+ return constant_a + scale * v;
83
+ }
84
+
85
+ inline uint hash_u32(uint x)
86
+ {
87
+ x ^= x >> 16;
88
+ x *= 0x7feb352du;
89
+ x ^= x >> 15;
90
+ x *= 0x846ca68bu;
91
+ x ^= x >> 16;
92
+ return x;
93
+ }
94
+
95
+ inline float random01(uint x)
96
+ {
97
+ return (float)(hash_u32(x) & 0x00ffffffu) * (1.0f / 16777216.0f);
98
+ }
99
+
100
+ __kernel void const_drag_force(
101
+ __global const float *V,
102
+ __global const float *M,
103
+ float cax,
104
+ float cay,
105
+ float caz,
106
+ float K,
107
+ int accumulate,
108
+ __global float *A)
109
+ {
110
+ int i = get_global_id(0);
111
+ int i0 = 3*i;
112
+ float3 v = (float3)(V[i0], V[i0+1], V[i0+2]);
113
+ float3 ca = (float3)(cax, cay, caz);
114
+ float3 a = const_drag_accel(v, M[i], ca, K);
115
+
116
+ if (accumulate)
117
+ {
118
+ A[i0] += a.x;
119
+ A[i0+1] += a.y;
120
+ A[i0+2] += a.z;
121
+ }
122
+ else
123
+ {
124
+ A[i0] = a.x;
125
+ A[i0+1] = a.y;
126
+ A[i0+2] = a.z;
127
+ }
128
+ }
129
+
130
+ __kernel void const_drag_euler(
131
+ __global float *V,
132
+ __global const float *M,
133
+ float cax,
134
+ float cay,
135
+ float caz,
136
+ float K,
137
+ float dt,
138
+ __global float *X)
139
+ {
140
+ int i = get_global_id(0);
141
+ int i0 = 3*i;
142
+
143
+ float3 v = (float3)(V[i0], V[i0+1], V[i0+2]);
144
+ float3 ca = (float3)(cax, cay, caz);
145
+ float3 a = const_drag_accel(v, M[i], ca, K);
146
+
147
+ v += a * dt;
148
+ V[i0] = v.x;
149
+ V[i0+1] = v.y;
150
+ V[i0+2] = v.z;
151
+
152
+ X[i0] += v.x * dt;
153
+ X[i0+1] += v.y * dt;
154
+ X[i0+2] += v.z * dt;
155
+ }
156
+
157
+ __kernel void const_drag_euler_fountain(
158
+ __global float *V,
159
+ __global const float *M,
160
+ float cax,
161
+ float cay,
162
+ float caz,
163
+ float K,
164
+ float dt,
165
+ float sim_time,
166
+ uint step,
167
+ float xmin,
168
+ float xmax,
169
+ float ymin,
170
+ float ymax,
171
+ float zmin,
172
+ float zmax,
173
+ __global float *X)
174
+ {
175
+ int i = get_global_id(0);
176
+ int i0 = 3*i;
177
+
178
+ float3 x = (float3)(X[i0], X[i0+1], X[i0+2]);
179
+ float3 v = (float3)(V[i0], V[i0+1], V[i0+2]);
180
+ float3 ca = (float3)(cax, cay, caz);
181
+ float3 a = const_drag_accel(v, M[i], ca, K);
182
+
183
+ v += a * dt;
184
+ x += v * dt;
185
+
186
+ int outside = (
187
+ x.x < xmin || x.x > xmax ||
188
+ x.y < ymin || x.y > ymax ||
189
+ x.z < zmin || x.z > zmax
190
+ );
191
+
192
+ if (outside)
193
+ {
194
+ uint seed = ((uint)i + 1u) * 747796405u ^ (step + 1u) * 2891336453u;
195
+ float rx = random01(seed ^ 0x68bc21ebu);
196
+ float ry = random01(seed ^ 0x02e5be93u);
197
+ float rz = random01(seed ^ 0x967a889bu);
198
+ float ra = random01(seed ^ 0x4f1bbcdcu);
199
+ float rv = random01(seed ^ 0x85ebca6bu);
200
+
201
+ x = (float3)(0.01f*rx, 0.01f*ry, 0.01f*rz);
202
+
203
+ float fs = 1.0f / (1.0f + exp(-(sim_time*4.0f - 2.0f)));
204
+ float alpha = 6.2831853071795864769f * ra;
205
+ v.x = 2.0f * fs * cos(alpha);
206
+ v.y = 2.0f * fs * sin(alpha);
207
+ v.z = 10.0f * fs + fs * rv;
208
+ }
209
+
210
+ V[i0] = v.x;
211
+ V[i0+1] = v.y;
212
+ V[i0+2] = v.z;
213
+ X[i0] = x.x;
214
+ X[i0+1] = x.y;
215
+ X[i0+2] = x.z;
216
+ }
217
+
218
+ __kernel void const_drag_euler_fountain_render(
219
+ __global float *V,
220
+ __global const float *M,
221
+ float cax,
222
+ float cay,
223
+ float caz,
224
+ float K,
225
+ float dt,
226
+ float sim_time,
227
+ uint step,
228
+ float xmin,
229
+ float xmax,
230
+ float ymin,
231
+ float ymax,
232
+ float zmin,
233
+ float zmax,
234
+ __global float *X,
235
+ __global float *render_X)
236
+ {
237
+ int i = get_global_id(0);
238
+ int i0 = 3*i;
239
+
240
+ float3 x = (float3)(X[i0], X[i0+1], X[i0+2]);
241
+ float3 v = (float3)(V[i0], V[i0+1], V[i0+2]);
242
+ float3 ca = (float3)(cax, cay, caz);
243
+ float3 a = const_drag_accel(v, M[i], ca, K);
244
+
245
+ v += a * dt;
246
+ x += v * dt;
247
+
248
+ int outside = (
249
+ x.x < xmin || x.x > xmax ||
250
+ x.y < ymin || x.y > ymax ||
251
+ x.z < zmin || x.z > zmax
252
+ );
253
+
254
+ if (outside)
255
+ {
256
+ uint seed = ((uint)i + 1u) * 747796405u ^ (step + 1u) * 2891336453u;
257
+ float rx = random01(seed ^ 0x68bc21ebu);
258
+ float ry = random01(seed ^ 0x02e5be93u);
259
+ float rz = random01(seed ^ 0x967a889bu);
260
+ float ra = random01(seed ^ 0x4f1bbcdcu);
261
+ float rv = random01(seed ^ 0x85ebca6bu);
262
+
263
+ x = (float3)(0.01f*rx, 0.01f*ry, 0.01f*rz);
264
+
265
+ float fs = 1.0f / (1.0f + exp(-(sim_time*4.0f - 2.0f)));
266
+ float alpha = 6.2831853071795864769f * ra;
267
+ v.x = 2.0f * fs * cos(alpha);
268
+ v.y = 2.0f * fs * sin(alpha);
269
+ v.z = 10.0f * fs + fs * rv;
270
+ }
271
+
272
+ V[i0] = v.x;
273
+ V[i0+1] = v.y;
274
+ V[i0+2] = v.z;
275
+
276
+ X[i0] = x.x;
277
+ X[i0+1] = x.y;
278
+ X[i0+2] = x.z;
279
+
280
+ render_X[i0] = x.x;
281
+ render_X[i0+1] = x.y;
282
+ render_X[i0+2] = x.z;
283
+ }
284
+ """
285
+ self.__program = cl.Program(self.__occ.CL_context, source).build()
286
+ self.__force_kernel = cl.Kernel(self.__program, "const_drag_force")
287
+ self.__euler_kernel = cl.Kernel(self.__program, "const_drag_euler")
288
+ self.__fountain_kernel = cl.Kernel(
289
+ self.__program, "const_drag_euler_fountain"
290
+ )
291
+ self.__fountain_render_kernel = cl.Kernel(
292
+ self.__program, "const_drag_euler_fountain_render"
293
+ )
294
+
295
+ def set_masses(self, m):
296
+ self.__M[:] = np.asarray(m, dtype=self.__dtype)
297
+ self.__occ.set_from_host("M", self.__M)
298
+
299
+ def _common_args(self):
300
+ return (
301
+ self.__dtype(self.__UF[0]),
302
+ self.__dtype(self.__UF[1]),
303
+ self.__dtype(self.__UF[2]),
304
+ self.__K,
305
+ )
306
+
307
+ def set_render_target(self, buffer, wait_for=None):
308
+ """Mirror the next fountain step's final X values into *buffer*.
309
+
310
+ The target is one-shot and is cleared as soon as the next step is
311
+ enqueued. ``wait_for`` may contain an OpenCL GL-acquire event so the
312
+ kernel cannot write the shared object before OpenCL owns it.
313
+ """
314
+ if self.__fountain_bounds is None:
315
+ raise RuntimeError("A render target is supported only in fountain mode")
316
+ if buffer is None:
317
+ self.clear_render_target()
318
+ return
319
+ self.__render_target = buffer
320
+ self.__render_wait_for = None if wait_for is None else list(wait_for)
321
+
322
+ def clear_render_target(self):
323
+ self.__render_target = None
324
+ self.__render_wait_for = None
325
+
326
+ def update_force_device(self, pset, accumulate=False, host_authoritative=False):
327
+ if host_authoritative:
328
+ self.__occ.mark_host_modified("V")
329
+ self.__occ.sync_to_device("V", pset.V)
330
+
331
+ cax, cay, caz, drag_const = self._common_args()
332
+ self.__force_kernel(
333
+ self.__occ.CL_queue,
334
+ (self.__size,),
335
+ None,
336
+ self.__occ.V_cla.data,
337
+ self.__occ.M_cla.data,
338
+ cax,
339
+ cay,
340
+ caz,
341
+ drag_const,
342
+ np.int32(bool(accumulate)),
343
+ self.__occ.A_cla.data,
344
+ )
345
+ self.__occ.mark_device_modified("A")
346
+ return self.__occ.A_cla
347
+
348
+ def euler_step_device(self, pset, dt, sim_time=None, step=None):
349
+ """Evaluate force and advance X/V in one device kernel launch."""
350
+ cax, cay, caz, drag_const = self._common_args()
351
+
352
+ if self.__fountain_bounds is None:
353
+ self.__last_step_event = self.__euler_kernel(
354
+ self.__occ.CL_queue,
355
+ (self.__size,),
356
+ None,
357
+ self.__occ.V_cla.data,
358
+ self.__occ.M_cla.data,
359
+ cax,
360
+ cay,
361
+ caz,
362
+ drag_const,
363
+ self.__dtype(dt),
364
+ self.__occ.X_cla.data,
365
+ )
366
+ else:
367
+ b = self.__fountain_bounds
368
+ render_target = self.__render_target
369
+ render_wait_for = self.__render_wait_for
370
+ self.clear_render_target()
371
+
372
+ args = (
373
+ self.__occ.V_cla.data,
374
+ self.__occ.M_cla.data,
375
+ cax,
376
+ cay,
377
+ caz,
378
+ drag_const,
379
+ self.__dtype(dt),
380
+ self.__dtype(0.0 if sim_time is None else sim_time),
381
+ np.uint32(0 if step is None else step),
382
+ self.__dtype(b[0]),
383
+ self.__dtype(b[1]),
384
+ self.__dtype(b[2]),
385
+ self.__dtype(b[3]),
386
+ self.__dtype(b[4]),
387
+ self.__dtype(b[5]),
388
+ self.__occ.X_cla.data,
389
+ )
390
+
391
+ if render_target is None:
392
+ self.__last_step_event = self.__fountain_kernel(
393
+ self.__occ.CL_queue,
394
+ (self.__size,),
395
+ None,
396
+ *args
397
+ )
398
+ else:
399
+ self.__last_step_event = self.__fountain_render_kernel(
400
+ self.__occ.CL_queue,
401
+ (self.__size,),
402
+ None,
403
+ *args,
404
+ render_target,
405
+ wait_for=render_wait_for,
406
+ )
407
+
408
+ self.__occ.mark_device_modified("X")
409
+ self.__occ.mark_device_modified("V")
410
+ return self.__occ.X_cla, self.__occ.V_cla
411
+
412
+ def update_force(self, pset):
413
+ self.update_force_device(pset, accumulate=False, host_authoritative=True)
414
+ self.__occ.sync_to_host("A", self.__A)
415
+ return self.__A
416
+
417
+ def getA(self):
418
+ self.__occ.sync_to_host("A", self.__A)
419
+ return self.__A
420
+
421
+ A = property(getA)
422
+
423
+ def getF(self):
424
+ self.__occ.sync_to_host("A", self.__A)
425
+ return self.__A * self.__M
426
+
427
+ F = property(getF)
428
+
429
+ def get_ocl_context(self):
430
+ return self.__occ
431
+
432
+ ocl_context = property(get_ocl_context)
433
+
434
+ def get_fountain_bounds(self):
435
+ if self.__fountain_bounds is None:
436
+ return None
437
+ return tuple(float(value) for value in self.__fountain_bounds)
438
+
439
+ fountain_bounds = property(get_fountain_bounds)
440
+
441
+ def get_last_step_event(self):
442
+ """Return the most recently enqueued fused Euler OpenCL event."""
443
+ return self.__last_step_event
444
+
445
+ last_step_event = property(get_last_step_event)