PyParticles3 0.4.0rc1__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 +335 -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 +87 -0
- pyparticles/utils/time_formatter.py +50 -0
- pyparticles3-0.4.0rc1.dist-info/METADATA +196 -0
- pyparticles3-0.4.0rc1.dist-info/RECORD +100 -0
- pyparticles3-0.4.0rc1.dist-info/WHEEL +5 -0
- pyparticles3-0.4.0rc1.dist-info/entry_points.txt +3 -0
- pyparticles3-0.4.0rc1.dist-info/licenses/LICENSE-gpl-3.0.txt +674 -0
- pyparticles3-0.4.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,243 @@
|
|
|
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
|
+
"""Compatibility layer for the legacy PyParticles OpenGL animation.
|
|
10
|
+
|
|
11
|
+
The historical renderer is kept intact. This module adapts the pieces whose
|
|
12
|
+
runtime behaviour changed between the 2012 PyOpenGL/GLUT stack and current
|
|
13
|
+
FreeGLUT/PyOpenGL/NumPy releases. It also provides lifecycle hooks needed to
|
|
14
|
+
create OpenCL/OpenGL shared resources after the GL context exists.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import ctypes
|
|
18
|
+
import gc
|
|
19
|
+
import signal
|
|
20
|
+
|
|
21
|
+
import pyparticles.animation.animated_ogl as legacy
|
|
22
|
+
import pyparticles.ogl.draw_particles_ogl as legacy_draw
|
|
23
|
+
import pyparticles.ogl.draw_particles_ogl_compat as draw_compat
|
|
24
|
+
import pyparticles.ogl.draw_vector_field as legacy_vector_field
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
legacy_draw.DrawParticlesGL = draw_compat.DrawParticlesGL
|
|
28
|
+
legacy_draw.charged_particles_color = draw_compat.charged_particles_color
|
|
29
|
+
legacy_draw.charged_particles_vect_color = draw_compat.charged_particles_vect_color
|
|
30
|
+
legacy.drp.DrawParticlesGL = draw_compat.DrawParticlesGL
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _safe_vector_field_del(self):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
legacy_vector_field.DrawVectorField.__del__ = _safe_vector_field_del
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
_legacy_key_pressed = legacy.KeyPressed
|
|
41
|
+
_active_animation = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _cleanup_active_animation():
|
|
45
|
+
animation = _active_animation
|
|
46
|
+
if animation is None:
|
|
47
|
+
return
|
|
48
|
+
cleanup = getattr(animation, "cleanup_resources", None)
|
|
49
|
+
if cleanup is not None:
|
|
50
|
+
cleanup()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _leave_main_loop():
|
|
54
|
+
"""Request a clean FreeGLUT exit when the extension is available."""
|
|
55
|
+
leave = getattr(legacy, "glutLeaveMainLoop", None)
|
|
56
|
+
if leave is not None:
|
|
57
|
+
try:
|
|
58
|
+
if bool(leave):
|
|
59
|
+
leave()
|
|
60
|
+
return
|
|
61
|
+
except Exception:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
raise KeyboardInterrupt
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _key_pressed(key, x, y):
|
|
68
|
+
"""Adapt modern PyOpenGL byte keyboard callbacks to the legacy handler."""
|
|
69
|
+
if isinstance(key, bytes):
|
|
70
|
+
key = key.decode("latin-1")
|
|
71
|
+
|
|
72
|
+
if key in ("q", "Q", "\x1b"):
|
|
73
|
+
# Shared CL/GL objects must be released while the GLUT window and its
|
|
74
|
+
# GLX context are still alive. Calling glutLeaveMainLoop first may
|
|
75
|
+
# destroy the context before Python finally-block cleanup runs.
|
|
76
|
+
_cleanup_active_animation()
|
|
77
|
+
_leave_main_loop()
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
return _legacy_key_pressed(key, x, y)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _sigint_handler(signum, frame):
|
|
84
|
+
_cleanup_active_animation()
|
|
85
|
+
_leave_main_loop()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _close_window():
|
|
89
|
+
# FreeGLUT invokes the close callback as part of window destruction.
|
|
90
|
+
# Do not call glutLeaveMainLoop() recursively from here: that re-enters
|
|
91
|
+
# FreeGLUT's teardown path and can segfault with shared GL/CL resources.
|
|
92
|
+
_cleanup_active_animation()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _configure_freeglut_exit():
|
|
96
|
+
"""Ask FreeGLUT to return from its main loop when a window is closed."""
|
|
97
|
+
set_option = getattr(legacy, "glutSetOption", None)
|
|
98
|
+
action_key = getattr(legacy, "GLUT_ACTION_ON_WINDOW_CLOSE", None)
|
|
99
|
+
return_action = getattr(legacy, "GLUT_ACTION_GLUTMAINLOOP_RETURNS", None)
|
|
100
|
+
|
|
101
|
+
if set_option is not None and action_key is not None and return_action is not None:
|
|
102
|
+
try:
|
|
103
|
+
if bool(set_option):
|
|
104
|
+
set_option(action_key, return_action)
|
|
105
|
+
except Exception:
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
close_func = getattr(legacy, "glutCloseFunc", None)
|
|
109
|
+
if close_func is not None:
|
|
110
|
+
try:
|
|
111
|
+
if bool(close_func):
|
|
112
|
+
close_func(_close_window)
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class AnimatedGl(legacy.AnimatedGl):
|
|
118
|
+
"""Legacy renderer with modern FreeGLUT and CL/GL lifecycle hooks."""
|
|
119
|
+
|
|
120
|
+
def __init__(self):
|
|
121
|
+
super(AnimatedGl, self).__init__()
|
|
122
|
+
self.__gl_context_ready_callback = None
|
|
123
|
+
self.__pre_step_callback = None
|
|
124
|
+
self.__post_step_callback = None
|
|
125
|
+
self.__cleanup_callbacks = []
|
|
126
|
+
self.__cleanup_done = False
|
|
127
|
+
|
|
128
|
+
def get_trajectory_step(self):
|
|
129
|
+
return legacy.pan.Animation.get_trajectory_step(self)
|
|
130
|
+
|
|
131
|
+
def set_trajectory_step(self, value):
|
|
132
|
+
legacy.pan.Animation.set_trajectory_step(self, value)
|
|
133
|
+
self.draw_particles.set_trajectory_step(value)
|
|
134
|
+
|
|
135
|
+
trajectory_step = property(get_trajectory_step, set_trajectory_step)
|
|
136
|
+
|
|
137
|
+
def set_gl_context_ready_callback(self, callback):
|
|
138
|
+
"""Run *callback(animation)* immediately after GLUT creates the window.
|
|
139
|
+
|
|
140
|
+
At that point the GL context is current, but the legacy builder has not
|
|
141
|
+
yet called ``ode_solver.update_force()``. A callback may therefore
|
|
142
|
+
create a GL-sharing OpenCL context and replace ``animation.ode_solver``
|
|
143
|
+
before the first force evaluation.
|
|
144
|
+
"""
|
|
145
|
+
self.__gl_context_ready_callback = callback
|
|
146
|
+
|
|
147
|
+
def set_pre_step_callback(self, callback):
|
|
148
|
+
"""Run *callback(animation)* immediately before each solver step."""
|
|
149
|
+
self.__pre_step_callback = callback
|
|
150
|
+
|
|
151
|
+
def set_post_step_callback(self, callback):
|
|
152
|
+
"""Run *callback(animation)* after each solver step and before draw."""
|
|
153
|
+
self.__post_step_callback = callback
|
|
154
|
+
|
|
155
|
+
def add_cleanup_callback(self, callback):
|
|
156
|
+
self.__cleanup_callbacks.append(callback)
|
|
157
|
+
|
|
158
|
+
def cleanup_resources(self):
|
|
159
|
+
"""Release GL-dependent resources exactly once while GL is current."""
|
|
160
|
+
if self.__cleanup_done:
|
|
161
|
+
return
|
|
162
|
+
self.__cleanup_done = True
|
|
163
|
+
|
|
164
|
+
# No more CL/GL work may be scheduled once teardown starts.
|
|
165
|
+
self.__pre_step_callback = None
|
|
166
|
+
self.__post_step_callback = None
|
|
167
|
+
|
|
168
|
+
# Consume cleanup closures while the GL context is still current.
|
|
169
|
+
# Keeping an already-executed closure in this list can retain OpenCL
|
|
170
|
+
# kernels/contexts until after FreeGLUT destroys GLX, which is unsafe
|
|
171
|
+
# for objects derived from cl_khr_gl_sharing on the NVIDIA driver.
|
|
172
|
+
while self.__cleanup_callbacks:
|
|
173
|
+
callback = self.__cleanup_callbacks.pop()
|
|
174
|
+
try:
|
|
175
|
+
callback(self)
|
|
176
|
+
except Exception:
|
|
177
|
+
pass
|
|
178
|
+
finally:
|
|
179
|
+
callback = None
|
|
180
|
+
|
|
181
|
+
# Collect any cycles released by the callbacks before returning to the
|
|
182
|
+
# key/close handler that asks FreeGLUT to tear down the GL context.
|
|
183
|
+
gc.collect()
|
|
184
|
+
|
|
185
|
+
def build_animation(self):
|
|
186
|
+
global _active_animation
|
|
187
|
+
|
|
188
|
+
legacy.ctypes = ctypes
|
|
189
|
+
legacy.KeyPressed = _key_pressed
|
|
190
|
+
self.__cleanup_done = False
|
|
191
|
+
_active_animation = self
|
|
192
|
+
|
|
193
|
+
# The legacy builder creates the GLUT window and immediately evaluates
|
|
194
|
+
# the force. Wrap just the window creation call so CL/GL resources can
|
|
195
|
+
# be established in the narrow interval where the GL context is current
|
|
196
|
+
# and before the solver is first used.
|
|
197
|
+
original_create_window = legacy.glutCreateWindow
|
|
198
|
+
|
|
199
|
+
def create_window_with_hook(*args, **kwargs):
|
|
200
|
+
window = original_create_window(*args, **kwargs)
|
|
201
|
+
callback = self.__gl_context_ready_callback
|
|
202
|
+
if callback is not None:
|
|
203
|
+
callback(self)
|
|
204
|
+
return window
|
|
205
|
+
|
|
206
|
+
legacy.glutCreateWindow = create_window_with_hook
|
|
207
|
+
try:
|
|
208
|
+
result = super(AnimatedGl, self).build_animation()
|
|
209
|
+
finally:
|
|
210
|
+
legacy.glutCreateWindow = original_create_window
|
|
211
|
+
|
|
212
|
+
_configure_freeglut_exit()
|
|
213
|
+
return result
|
|
214
|
+
|
|
215
|
+
def data_stream(self):
|
|
216
|
+
callback = self.__pre_step_callback
|
|
217
|
+
if callback is not None:
|
|
218
|
+
callback(self)
|
|
219
|
+
|
|
220
|
+
result = super(AnimatedGl, self).data_stream()
|
|
221
|
+
|
|
222
|
+
callback = self.__post_step_callback
|
|
223
|
+
if callback is not None:
|
|
224
|
+
callback(self)
|
|
225
|
+
return result
|
|
226
|
+
|
|
227
|
+
def start(self):
|
|
228
|
+
global _active_animation
|
|
229
|
+
|
|
230
|
+
previous_sigint = signal.getsignal(signal.SIGINT)
|
|
231
|
+
signal.signal(signal.SIGINT, _sigint_handler)
|
|
232
|
+
_active_animation = self
|
|
233
|
+
try:
|
|
234
|
+
return super(AnimatedGl, self).start()
|
|
235
|
+
except KeyboardInterrupt:
|
|
236
|
+
return None
|
|
237
|
+
finally:
|
|
238
|
+
# This is a fallback for non-keyboard exits. Normal q/Esc and
|
|
239
|
+
# close-window paths have already run cleanup while GL was current.
|
|
240
|
+
self.cleanup_resources()
|
|
241
|
+
if _active_animation is self:
|
|
242
|
+
_active_animation = None
|
|
243
|
+
signal.signal(signal.SIGINT, previous_sigint)
|
|
@@ -0,0 +1,94 @@
|
|
|
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 pyparticles.pset.particles_set as ps
|
|
18
|
+
|
|
19
|
+
import pyparticles.animation.animation as pan
|
|
20
|
+
|
|
21
|
+
#import pyparticles.rand_cluster as clu
|
|
22
|
+
#import pyparticles.euler_solver as els
|
|
23
|
+
#import pyparticles.leapfrog_solver as lps
|
|
24
|
+
#import pyparticles.runge_kutta_solver as rks
|
|
25
|
+
|
|
26
|
+
import matplotlib.animation as animation
|
|
27
|
+
|
|
28
|
+
from mpl_toolkits.mplot3d import Axes3D
|
|
29
|
+
import matplotlib.pyplot as plt
|
|
30
|
+
import numpy as np
|
|
31
|
+
#import pyparticles.periodic_boundary as pb
|
|
32
|
+
#import pyparticles.rebound_boundary as rb
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
FLOOR = -10
|
|
37
|
+
CEILING = 10
|
|
38
|
+
|
|
39
|
+
class AnimatedScatter( pan.Animation ):
|
|
40
|
+
|
|
41
|
+
def __init__(self, numpoints=50):
|
|
42
|
+
super( AnimatedScatter , self ).__init__()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def build_animation(self):
|
|
46
|
+
self.fig = plt.figure()
|
|
47
|
+
self.ax = self.fig.add_subplot(111, projection='3d')
|
|
48
|
+
|
|
49
|
+
self.stream = self.data_stream()
|
|
50
|
+
|
|
51
|
+
self.ani = animation.FuncAnimation(self.fig, self.update, interval=5,
|
|
52
|
+
init_func=self.setup_plot, blit=True)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def setup_plot(self):
|
|
56
|
+
|
|
57
|
+
j = next(self.stream)
|
|
58
|
+
self.scat = self.ax.scatter( self.pset.X[:,0]/self.pset.unit ,
|
|
59
|
+
self.pset.X[:,1]/self.pset.unit ,
|
|
60
|
+
self.pset.X[:,2]/self.pset.unit ,
|
|
61
|
+
animated=True , marker='o' , alpha=None , s=10)
|
|
62
|
+
|
|
63
|
+
self.ax.set_xlim3d( self.xlim )
|
|
64
|
+
self.ax.set_ylim3d( self.ylim )
|
|
65
|
+
self.ax.set_zlim3d( self.zlim )
|
|
66
|
+
|
|
67
|
+
return self.scat,
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def data_stream(self):
|
|
71
|
+
|
|
72
|
+
self.ode_solver.update_force()
|
|
73
|
+
|
|
74
|
+
for j in range(self.steps):
|
|
75
|
+
self.ode_solver.step()
|
|
76
|
+
yield j
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def update(self, i):
|
|
81
|
+
"""Update the scatter plot."""
|
|
82
|
+
j = next(self.stream)
|
|
83
|
+
|
|
84
|
+
self.scat._offsets3d = ( np.ma.ravel(self.pset.X[:,0]/self.pset.unit) ,
|
|
85
|
+
np.ma.ravel(self.pset.X[:,1]/self.pset.unit) ,
|
|
86
|
+
np.ma.ravel(self.pset.X[:,2]/self.pset.unit)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
plt.draw()
|
|
90
|
+
return self.scat,
|
|
91
|
+
|
|
92
|
+
def start(self):
|
|
93
|
+
plt.show()
|
|
94
|
+
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# PyParticles : Particles simulation in python
|
|
4
|
+
# Copyright (C) 2012 Simone Riva
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import time
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Animation(object):
|
|
25
|
+
"""
|
|
26
|
+
Base abstract class used for controling the simulation.
|
|
27
|
+
This class should be used as a base class for building and runnig a simulation problem.
|
|
28
|
+
The class animation contains all foudamental element for working with a PyParticles in an easy way.
|
|
29
|
+
The user must overide the methods:
|
|
30
|
+
build_animation: For setting up averithing
|
|
31
|
+
data_stream: for performing a simulation step or runnig the main loop
|
|
32
|
+
start: start the smulation
|
|
33
|
+
|
|
34
|
+
In a few word you must follow this procedure:
|
|
35
|
+
::
|
|
36
|
+
|
|
37
|
+
# Construct a new object
|
|
38
|
+
a = MyAnimation()
|
|
39
|
+
|
|
40
|
+
# setup the particles set
|
|
41
|
+
a.pset = pset
|
|
42
|
+
|
|
43
|
+
# setup the numeric integration
|
|
44
|
+
a.ode_solver = solver
|
|
45
|
+
|
|
46
|
+
# max number of steps
|
|
47
|
+
a.steps = steps
|
|
48
|
+
|
|
49
|
+
# set up everythings
|
|
50
|
+
a.build_animation()
|
|
51
|
+
|
|
52
|
+
# start!
|
|
53
|
+
a.start()
|
|
54
|
+
"""
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.__ode_solver = None
|
|
57
|
+
self.__pset = None
|
|
58
|
+
self.__steps = 10000
|
|
59
|
+
|
|
60
|
+
self.__xl = (-1,1)
|
|
61
|
+
self.__yl = (-1,1)
|
|
62
|
+
self.__zl = (-1,1)
|
|
63
|
+
|
|
64
|
+
self.__trajectory = False
|
|
65
|
+
self.__trajectory_step = 1
|
|
66
|
+
|
|
67
|
+
self.__measures = dict()
|
|
68
|
+
self.__measures_names = []
|
|
69
|
+
|
|
70
|
+
self.__fps = 0.0
|
|
71
|
+
self.__fps_init_time = 0.0
|
|
72
|
+
self.__fps_steps = 7
|
|
73
|
+
self.__fps_cnt = 0
|
|
74
|
+
self.__fps_print = False
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def set_ode_solver( self , solver ):
|
|
78
|
+
self.__ode_solver = solver
|
|
79
|
+
|
|
80
|
+
def get_ode_solver( self ):
|
|
81
|
+
return self.__ode_solver
|
|
82
|
+
|
|
83
|
+
ode_solver = property( get_ode_solver , set_ode_solver )
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def add_measure( self , measure ):
|
|
87
|
+
"""
|
|
88
|
+
Add a class delegeted for performing a measure
|
|
89
|
+
"""
|
|
90
|
+
self.__measures[measure.name()] = measure
|
|
91
|
+
self.__measures_names.append( measure.name() )
|
|
92
|
+
|
|
93
|
+
def perform_measurement( self ):
|
|
94
|
+
"""
|
|
95
|
+
Execute all listed measures
|
|
96
|
+
"""
|
|
97
|
+
for m in self.__measures_names :
|
|
98
|
+
self.__measures[m].pset = self.pset
|
|
99
|
+
self.__measures[m].update_measure()
|
|
100
|
+
|
|
101
|
+
def get_measure_value( self , name ):
|
|
102
|
+
"""
|
|
103
|
+
get the value of the measure named 'name'
|
|
104
|
+
"""
|
|
105
|
+
return self.__measures[name].value()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_measure_value_str( self , name ):
|
|
109
|
+
"""
|
|
110
|
+
return a string containig the value of the measure
|
|
111
|
+
"""
|
|
112
|
+
return self.__measures[name].value_str()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_measure( self , name ):
|
|
116
|
+
"""
|
|
117
|
+
return the measure named 'name'
|
|
118
|
+
"""
|
|
119
|
+
return self.__measures[name]
|
|
120
|
+
|
|
121
|
+
def get_measures_names( self ):
|
|
122
|
+
"""
|
|
123
|
+
Return a list containg the names of the executed measured.
|
|
124
|
+
"""
|
|
125
|
+
return self.__measures_names
|
|
126
|
+
|
|
127
|
+
def measures_cnt( self ):
|
|
128
|
+
return len( self.__measures )
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def get_pset(self):
|
|
132
|
+
return self.__pset
|
|
133
|
+
|
|
134
|
+
def set_pset( self , pset ):
|
|
135
|
+
self.__pset = pset
|
|
136
|
+
|
|
137
|
+
pset = property( get_pset , set_pset )
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_steps( self ):
|
|
141
|
+
return self.__steps
|
|
142
|
+
|
|
143
|
+
def set_steps( self , steps ):
|
|
144
|
+
self.__steps = steps
|
|
145
|
+
|
|
146
|
+
steps = property( get_steps , set_steps )
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def update_fps(self):
|
|
150
|
+
"""
|
|
151
|
+
Update the FPS, this method must be called every step.
|
|
152
|
+
|
|
153
|
+
:returns: True if the FPS has been updated
|
|
154
|
+
"""
|
|
155
|
+
if self.__fps_cnt == 0 :
|
|
156
|
+
self.__fps_init_time = time.time()
|
|
157
|
+
self.__fps_cnt += 1
|
|
158
|
+
return False
|
|
159
|
+
|
|
160
|
+
elif self.__fps_cnt == self.__fps_steps :
|
|
161
|
+
et = time.time()
|
|
162
|
+
self.__fps = float(self.__fps_cnt) / ( et - self.__fps_init_time )
|
|
163
|
+
self.__fps_cnt = 0
|
|
164
|
+
return True
|
|
165
|
+
|
|
166
|
+
else :
|
|
167
|
+
self.__fps_cnt += 1
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
def get_fps(self):
|
|
171
|
+
return self.__fps
|
|
172
|
+
|
|
173
|
+
fps = property( get_fps , doc="get the current FPS" )
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_fps_steps(self):
|
|
177
|
+
return self.__fps_steps
|
|
178
|
+
|
|
179
|
+
def set_fps_steps( self , stp ):
|
|
180
|
+
self.__fps_steps = stp
|
|
181
|
+
|
|
182
|
+
fps_steps = property( get_fps_steps , set_fps_steps , doc="get and set the steps used for computing the fps" )
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_fps_print( self ):
|
|
186
|
+
return self.__fps_print
|
|
187
|
+
|
|
188
|
+
def set_fps_print( self , f ):
|
|
189
|
+
self.__fps_print = f
|
|
190
|
+
|
|
191
|
+
fps_print = property( get_fps_print , set_fps_print , doc="Toggle the printing of the FPS (True | False)")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def set_xlim( self , xl ):
|
|
195
|
+
self.__xl = xl
|
|
196
|
+
|
|
197
|
+
def get_xlim( self ):
|
|
198
|
+
return self.__xl
|
|
199
|
+
|
|
200
|
+
def set_ylim( self , yl ):
|
|
201
|
+
self.__yl = yl
|
|
202
|
+
|
|
203
|
+
def get_ylim( self ):
|
|
204
|
+
return self.__yl
|
|
205
|
+
|
|
206
|
+
def set_zlim( self , zl ):
|
|
207
|
+
self.__zl = zl
|
|
208
|
+
|
|
209
|
+
def get_zlim( self ):
|
|
210
|
+
return self.__zl
|
|
211
|
+
|
|
212
|
+
xlim = property( get_xlim , set_xlim )
|
|
213
|
+
ylim = property( get_ylim , set_ylim )
|
|
214
|
+
zlim = property( get_zlim , set_zlim )
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def get_trajectory( self ) :
|
|
218
|
+
return self.__trajectory
|
|
219
|
+
|
|
220
|
+
def set_trajectory( self , tr ):
|
|
221
|
+
self.__trajectory = tr
|
|
222
|
+
|
|
223
|
+
trajectory = property( get_trajectory , set_trajectory , doc="enable or disable the trajectory" )
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_trajectory_step( self ) :
|
|
227
|
+
return self.__trajectory_step
|
|
228
|
+
|
|
229
|
+
def set_trajectory_step( self , trs ):
|
|
230
|
+
self.__trajectory_step = trs
|
|
231
|
+
|
|
232
|
+
trajectory_step = property( get_trajectory_step , set_trajectory_step , doc="set or get the step for drawing the trajectory" )
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def build_animation(self):
|
|
236
|
+
NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
|
|
237
|
+
|
|
238
|
+
def data_stream(self):
|
|
239
|
+
NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
|
|
240
|
+
|
|
241
|
+
def closing_procedure(self):
|
|
242
|
+
NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
|
|
243
|
+
|
|
244
|
+
def start(self):
|
|
245
|
+
NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|