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.
- pyparticles/__init__.py +26 -0
- pyparticles/__main__.py +7 -0
- pyparticles/animation/__init__.py +21 -0
- pyparticles/animation/animated_cli.py +53 -0
- pyparticles/animation/animated_ogl.py +691 -0
- pyparticles/animation/animated_ogl_compat.py +243 -0
- pyparticles/animation/animated_scatter.py +94 -0
- pyparticles/animation/animation.py +251 -0
- pyparticles/animation/test_animation.py +310 -0
- pyparticles/demo/__init__.py +33 -0
- pyparticles/demo/bubble.py +106 -0
- pyparticles/demo/electromagnetic_demo.py +128 -0
- pyparticles/demo/electrostatic_demo.py +126 -0
- pyparticles/demo/fountain.py +478 -0
- pyparticles/demo/gas_lennard_jones.py +87 -0
- pyparticles/demo/gravity_clusters.py +73 -0
- pyparticles/demo/solar_system.py +222 -0
- pyparticles/demo/springs.py +141 -0
- pyparticles/demo/springs_constr.py +135 -0
- pyparticles/demo/test.py +34 -0
- pyparticles/forces/__init__.py +21 -0
- pyparticles/forces/const_force.py +140 -0
- pyparticles/forces/damping.py +174 -0
- pyparticles/forces/drag.py +167 -0
- pyparticles/forces/electromagnetic.py +105 -0
- pyparticles/forces/electromagnetic_field.py +95 -0
- pyparticles/forces/electrostatic.py +72 -0
- pyparticles/forces/force.py +75 -0
- pyparticles/forces/force_constrained.py +32 -0
- pyparticles/forces/fused_const_drag.py +445 -0
- pyparticles/forces/gravity.py +345 -0
- pyparticles/forces/lennard_jones.py +74 -0
- pyparticles/forces/linear_spring.py +86 -0
- pyparticles/forces/linear_spring_constrained.py +72 -0
- pyparticles/forces/multiple_force.py +134 -0
- pyparticles/forces/pseudo_bubble.py +226 -0
- pyparticles/forces/van_der_waals_force.py +60 -0
- pyparticles/forces/vector_field_force.py +52 -0
- pyparticles/geometry/__init__.py +21 -0
- pyparticles/geometry/dist.py +24 -0
- pyparticles/geometry/intersection.py +62 -0
- pyparticles/geometry/transformations.py +387 -0
- pyparticles/main/__init__.py +21 -0
- pyparticles/main/main.py +466 -0
- pyparticles/measures/__init__.py +21 -0
- pyparticles/measures/elastic_potential_energy.py +67 -0
- pyparticles/measures/gravitational_potential_energy.py +69 -0
- pyparticles/measures/kinetic_energy.py +68 -0
- pyparticles/measures/mass.py +59 -0
- pyparticles/measures/measure.py +156 -0
- pyparticles/measures/momentum.py +144 -0
- pyparticles/measures/total_energy.py +68 -0
- pyparticles/ode/__init__.py +21 -0
- pyparticles/ode/euler_solver.py +214 -0
- pyparticles/ode/euler_solver_constrained.py +49 -0
- pyparticles/ode/leapfrog_solver.py +37 -0
- pyparticles/ode/leapfrog_solver_constrained.py +53 -0
- pyparticles/ode/midpoint_solver.py +43 -0
- pyparticles/ode/midpoint_solver_constrained.py +60 -0
- pyparticles/ode/ode_solver.py +134 -0
- pyparticles/ode/ode_solver_constrained.py +43 -0
- pyparticles/ode/runge_kutta_solver.py +79 -0
- pyparticles/ode/runge_kutta_solver_constrained.py +98 -0
- pyparticles/ode/sim_time.py +56 -0
- pyparticles/ode/stormer_verlet_solver.py +50 -0
- pyparticles/ode/stormer_verlet_solver_constrained.py +73 -0
- pyparticles/ogl/__init__.py +21 -0
- pyparticles/ogl/axis_ogl.py +210 -0
- pyparticles/ogl/draw_particles_ogl.py +313 -0
- pyparticles/ogl/draw_particles_ogl_compat.py +509 -0
- pyparticles/ogl/draw_vector_field.py +221 -0
- pyparticles/ogl/opencl_gl_vbo.py +485 -0
- pyparticles/ogl/trackball.py +131 -0
- pyparticles/ogl/translate_scene.py +87 -0
- pyparticles/pset/__init__.py +21 -0
- pyparticles/pset/boundary.py +69 -0
- pyparticles/pset/cluster.py +28 -0
- pyparticles/pset/constrained_force_interactions.py +63 -0
- pyparticles/pset/constrained_x.py +158 -0
- pyparticles/pset/constraint.py +42 -0
- pyparticles/pset/default_boundary.py +43 -0
- pyparticles/pset/file_cluster.py +131 -0
- pyparticles/pset/logger.py +152 -0
- pyparticles/pset/octree.py +451 -0
- pyparticles/pset/opencl_context.py +374 -0
- pyparticles/pset/particles_set.py +499 -0
- pyparticles/pset/periodic_boundary.py +36 -0
- pyparticles/pset/rand_cluster.py +188 -0
- pyparticles/pset/rebound_boundary.py +68 -0
- pyparticles/utils/__init__.py +21 -0
- pyparticles/utils/parse_args.py +72 -0
- pyparticles/utils/problem_config.py +608 -0
- pyparticles/utils/pypart_global.py +122 -0
- pyparticles/utils/time_formatter.py +50 -0
- pyparticles3-0.4.0.dist-info/METADATA +395 -0
- pyparticles3-0.4.0.dist-info/RECORD +100 -0
- pyparticles3-0.4.0.dist-info/WHEEL +5 -0
- pyparticles3-0.4.0.dist-info/entry_points.txt +3 -0
- pyparticles3-0.4.0.dist-info/licenses/LICENSE-gpl-3.0.txt +674 -0
- 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)
|