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,499 @@
|
|
|
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 numpy as np
|
|
19
|
+
from collections import deque
|
|
20
|
+
|
|
21
|
+
import pyparticles.pset.logger as log
|
|
22
|
+
|
|
23
|
+
import random
|
|
24
|
+
import string
|
|
25
|
+
|
|
26
|
+
class ParticlesSet(object):
|
|
27
|
+
"""
|
|
28
|
+
The main class for storing the particles data set.
|
|
29
|
+
|
|
30
|
+
Constructor:
|
|
31
|
+
|
|
32
|
+
:param size: (default 1) Number of particles
|
|
33
|
+
:param dim: (default 3) dimensions of the system 2 or 3 ... 2D 3D
|
|
34
|
+
:param mass: (dafault True) if True the particles have a mass.
|
|
35
|
+
:param label: (default False) if true it's possible to set a name for each particle
|
|
36
|
+
:param velocity: (dafault True) if true the particles has a velocity
|
|
37
|
+
:param charge: (default False) if true the particles have an electric charge.
|
|
38
|
+
:param log_X: (default False) if true it's possible to logging the position
|
|
39
|
+
:param log_V: (default False) if true it's possible to logging the velocity
|
|
40
|
+
:param log_max_size: (default 0) set the maximal size of the log queue
|
|
41
|
+
:param dtype: (default np.float64) the floating point type ot the set
|
|
42
|
+
|
|
43
|
+
.. note::
|
|
44
|
+
|
|
45
|
+
The properties: position X and velocity V are mandatory.
|
|
46
|
+
"""
|
|
47
|
+
def __init__( self , size=1 , dim=3 , boundary=None ,
|
|
48
|
+
label=False , mass=True , velocity=True , charge=False ,
|
|
49
|
+
log_X=False , log_V=False , log_max_size=0 , dtype=np.float64 ):
|
|
50
|
+
|
|
51
|
+
if size < 0 :
|
|
52
|
+
raise
|
|
53
|
+
|
|
54
|
+
self.__dtype = dtype
|
|
55
|
+
|
|
56
|
+
self.__X = np.zeros((size,dim) , dtype=dtype )
|
|
57
|
+
|
|
58
|
+
if velocity:
|
|
59
|
+
self.__V = np.zeros((size,dim) , dtype=dtype )
|
|
60
|
+
else:
|
|
61
|
+
self.__V = None
|
|
62
|
+
|
|
63
|
+
if mass :
|
|
64
|
+
self.__mass = np.zeros((size,1) , dtype=dtype )
|
|
65
|
+
else:
|
|
66
|
+
self.__mass = None
|
|
67
|
+
|
|
68
|
+
if charge :
|
|
69
|
+
self.__Q = np.zeros(( size , 1 ) , dtype=dtype )
|
|
70
|
+
else:
|
|
71
|
+
self.__Q = None
|
|
72
|
+
|
|
73
|
+
if not label :
|
|
74
|
+
self.__label = None
|
|
75
|
+
else:
|
|
76
|
+
self.__label = list( "" for i in range(size) )
|
|
77
|
+
|
|
78
|
+
self.__size = int( size )
|
|
79
|
+
self.__dim = int( dim )
|
|
80
|
+
self.__centre_mass = None
|
|
81
|
+
|
|
82
|
+
self.__bound = boundary
|
|
83
|
+
|
|
84
|
+
self.__unit = 1.0
|
|
85
|
+
self.__mass_unit = 1.0
|
|
86
|
+
|
|
87
|
+
self.__log = dict()
|
|
88
|
+
self.__default_logger = None
|
|
89
|
+
|
|
90
|
+
self.__property_dict = dict()
|
|
91
|
+
self.__property_dict['X'] = self.__X
|
|
92
|
+
self.__property_dict['V'] = self.__V
|
|
93
|
+
|
|
94
|
+
if self.__mass is not None :
|
|
95
|
+
self.__property_dict['M'] = self.__mass
|
|
96
|
+
|
|
97
|
+
if self.__label is not None :
|
|
98
|
+
self.__property_dict['label'] = self.__label
|
|
99
|
+
|
|
100
|
+
if self.__Q is not None :
|
|
101
|
+
self.__property_dict['Q'] = self.__Q
|
|
102
|
+
|
|
103
|
+
self.__notify_set_changed = []
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def realloc( self , size , dim , boundary=None ,
|
|
107
|
+
label=False , mass=True , velocity=True , charge=False ,
|
|
108
|
+
log_X=False , log_V=False , log_max_size=0 ):
|
|
109
|
+
"""
|
|
110
|
+
Realloc the particle set, it uses the same args of the constructor,
|
|
111
|
+
|
|
112
|
+
**Attention!** this method remove the dictionary of the of the extra properties
|
|
113
|
+
"""
|
|
114
|
+
del self.__X
|
|
115
|
+
del self.__V
|
|
116
|
+
del self.__mass
|
|
117
|
+
del self.__label
|
|
118
|
+
del self.__property_dict
|
|
119
|
+
|
|
120
|
+
self.__init__( size , dim , boundary , label , mass , velocity , charge , log_X , log_V , log_max_size )
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def resize( self , new_size ):
|
|
124
|
+
"""
|
|
125
|
+
Resize the particles set with the new_size.
|
|
126
|
+
|
|
127
|
+
If the new size is bigger the old data are copied in the new particles, according to the function numpy.resize
|
|
128
|
+
if it is smaller it cancels the data.
|
|
129
|
+
|
|
130
|
+
If the property is a list, the new elements will be filled with 'None' or empty string for the labels
|
|
131
|
+
|
|
132
|
+
The dim of the set will be not changed.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
for k in self.__property_dict.keys() :
|
|
136
|
+
if self.__property_dict[k] is None :
|
|
137
|
+
continue
|
|
138
|
+
|
|
139
|
+
if k == "label" :
|
|
140
|
+
lst = list( "" for i in range(new_size) )
|
|
141
|
+
|
|
142
|
+
mn = min( [ self.size , new_size ] )
|
|
143
|
+
lst[:mn] = self.__label[:mn]
|
|
144
|
+
|
|
145
|
+
self.__property_dict[k] = list( lst )
|
|
146
|
+
self.__label = lst
|
|
147
|
+
|
|
148
|
+
elif isinstance( self.__property_dict[k] , list ) :
|
|
149
|
+
lst = list( None for i in range(new_size) )
|
|
150
|
+
|
|
151
|
+
mn = min( [ self.size , new_size ] )
|
|
152
|
+
lst[:mn] = self.__property_dict[k][:mn]
|
|
153
|
+
self.__property_dict[k] = lst
|
|
154
|
+
|
|
155
|
+
else :
|
|
156
|
+
NP = np.resize( self.__property_dict[k] ,
|
|
157
|
+
( new_size , self.__property_dict[k].shape[1] ) )
|
|
158
|
+
self.__property_dict[k] = NP
|
|
159
|
+
|
|
160
|
+
if k == "M" :
|
|
161
|
+
self.__mass = NP
|
|
162
|
+
elif k == "X" :
|
|
163
|
+
self.__X = NP
|
|
164
|
+
elif k == "V" :
|
|
165
|
+
self.__V = NP
|
|
166
|
+
elif k == "Q" :
|
|
167
|
+
self.__Q = NP
|
|
168
|
+
|
|
169
|
+
self.__size = int( new_size )
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def get_by_name( self , property_name ):
|
|
173
|
+
"""
|
|
174
|
+
Return a property reference by name:
|
|
175
|
+
for example 'X' , 'V' , 'M' , 'Q' ...
|
|
176
|
+
|
|
177
|
+
:param property_name: The name of a property
|
|
178
|
+
|
|
179
|
+
::
|
|
180
|
+
|
|
181
|
+
# set to [1,2,3] the coordinates of the 10th particle
|
|
182
|
+
pset.get_by_name('X')[10,:] = [1,2,3]
|
|
183
|
+
"""
|
|
184
|
+
return self.__property_dict[property_name]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def add_property_by_name( self , property_name , dim=None , model="numpy_array" , to_type=None ):
|
|
188
|
+
"""
|
|
189
|
+
Insert a new property by name. If the dim is not specified it uses the current dimension of the set.
|
|
190
|
+
|
|
191
|
+
If the model of the property is 'list' the dim is forced to 1
|
|
192
|
+
|
|
193
|
+
:param property_name: the name of the new property
|
|
194
|
+
:param dim: the dimension of the new property ( 2 = "2D , 3 = 3D ... )
|
|
195
|
+
:param model: 'list' or 'numpy_array'
|
|
196
|
+
:param to_type: [self.dtype] an array-numpy type for the model 'numpy_array' [ np.float64 , np.int64 ... ]
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
For example add 'friction' or 'radius':
|
|
200
|
+
::
|
|
201
|
+
|
|
202
|
+
# Add the friction to the particles set
|
|
203
|
+
pset.add_property_by_name( "friction" , dim=1 , to_type=np.float32 )
|
|
204
|
+
pset.add_property_by_name( "radius" , dim=1 , to_type=np.float64 )
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
if to_type is None :
|
|
208
|
+
to_type = self.dtype
|
|
209
|
+
|
|
210
|
+
if dim is None :
|
|
211
|
+
dim = self.dim
|
|
212
|
+
|
|
213
|
+
if model == "numpy_array" :
|
|
214
|
+
self.__property_dict[property_name] = to_type( np.zeros(( self.size , dim ) ) )
|
|
215
|
+
elif model == "list" :
|
|
216
|
+
self.__property_dict[property_name] = list( None for i in range(self.size) )
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_properties_names(self):
|
|
220
|
+
"""
|
|
221
|
+
Return a list of containing the names of all properties
|
|
222
|
+
"""
|
|
223
|
+
return list( self.__property_dict.keys() )
|
|
224
|
+
|
|
225
|
+
def get_dtype(self):
|
|
226
|
+
return self.__dtype
|
|
227
|
+
|
|
228
|
+
dtype = property( get_dtype , doc="return the dtype of the set" )
|
|
229
|
+
|
|
230
|
+
def getX(self):
|
|
231
|
+
return self.__X
|
|
232
|
+
|
|
233
|
+
X = property( getX , doc="return the reference to the array of the positions" )
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def getM(self):
|
|
237
|
+
return self.__mass
|
|
238
|
+
|
|
239
|
+
M = property( getM , doc="return the reference to the array of the masses" )
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def getQ(self):
|
|
243
|
+
return self.__Q
|
|
244
|
+
|
|
245
|
+
Q = property( getQ , doc="return the reference to the array of the charges" )
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def getV(self):
|
|
249
|
+
return self.__V
|
|
250
|
+
|
|
251
|
+
V = property( getV , doc="return the reference to the velocities array" )
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def get_list( self , i , to=float ):
|
|
255
|
+
"""
|
|
256
|
+
return a list containing all data of the i-th particle
|
|
257
|
+
TODO: adapt to property by name
|
|
258
|
+
"""
|
|
259
|
+
#
|
|
260
|
+
#lst = []
|
|
261
|
+
#for k in self.__property_dict.keys() :
|
|
262
|
+
# pass
|
|
263
|
+
|
|
264
|
+
lstX = []
|
|
265
|
+
lstV = []
|
|
266
|
+
lstM = to( self.M[i] )
|
|
267
|
+
|
|
268
|
+
for j in range( self.dim ):
|
|
269
|
+
lstX.append( to( self.X[i,j] ) )
|
|
270
|
+
lstV.append( to( self.V[i,j] ) )
|
|
271
|
+
|
|
272
|
+
lst = lstX + lstV
|
|
273
|
+
lst.append( lstM )
|
|
274
|
+
|
|
275
|
+
if self.__label is not None :
|
|
276
|
+
lst.append( self.__label[i] )
|
|
277
|
+
|
|
278
|
+
return lst
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def get_label( self ):
|
|
282
|
+
return self.__label
|
|
283
|
+
|
|
284
|
+
label = property( get_label , doc="return the reference to the label list" )
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def append( self , p_dict ) :
|
|
288
|
+
"""
|
|
289
|
+
Append the particle(s) described in the given dictionary
|
|
290
|
+
|
|
291
|
+
If the particle don't contain every required data will be rejected.
|
|
292
|
+
|
|
293
|
+
The dictionary *p_dict* must contains the name of the property and it's value, and it **must include all property**, also the user defined!
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
for k in p_dict.keys():
|
|
297
|
+
if k not in self.__property_dict :
|
|
298
|
+
raise ValueError
|
|
299
|
+
|
|
300
|
+
for kpr in self.__property_dict.keys() :
|
|
301
|
+
if isinstance( self.__property_dict[kpr] , list ):
|
|
302
|
+
self.__property_dict[kpr].append( p_dict[kpr] )
|
|
303
|
+
else :
|
|
304
|
+
self.__property_dict[kpr] = np.append( self.__property_dict[kpr] , p_dict[kpr] , 0 )
|
|
305
|
+
if kpr == "X" :
|
|
306
|
+
self.__X = self.__property_dict[kpr]
|
|
307
|
+
elif kpr == "V" :
|
|
308
|
+
self.__V = self.__property_dict[kpr]
|
|
309
|
+
elif kpr == "M" :
|
|
310
|
+
self.__mass = self.__property_dict[kpr]
|
|
311
|
+
elif kpr == "Q" :
|
|
312
|
+
self.__Q = self.__property_dict[kpr]
|
|
313
|
+
|
|
314
|
+
self.notify_set_changed()
|
|
315
|
+
|
|
316
|
+
def notify_set_changed(self):
|
|
317
|
+
"""
|
|
318
|
+
Call this methods when the particle set is modified.
|
|
319
|
+
"""
|
|
320
|
+
for e in self.__notify_set_changed :
|
|
321
|
+
e.particles_set_changed( self )
|
|
322
|
+
|
|
323
|
+
def add_set_changed_listener( self , listener ) :
|
|
324
|
+
"""
|
|
325
|
+
Add an object that contains a member methods called: *particles_set_changed( pset )* that there will be called if the particle set is modified.
|
|
326
|
+
"""
|
|
327
|
+
self.__notify_set_changed.append( listener )
|
|
328
|
+
|
|
329
|
+
def update_boundary( self ):
|
|
330
|
+
"""
|
|
331
|
+
Update the particle set according to the boundary rule
|
|
332
|
+
"""
|
|
333
|
+
if self.__bound is not None :
|
|
334
|
+
self.__bound.boundary( self )
|
|
335
|
+
|
|
336
|
+
def get_boundary( self ):
|
|
337
|
+
return self.__bound
|
|
338
|
+
|
|
339
|
+
def set_boundary( self , boundary):
|
|
340
|
+
self.__bound = boundary
|
|
341
|
+
|
|
342
|
+
boundary = property( get_boundary , set_boundary , doc="return the reference to the boundary, None if the boundary are not set or open")
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def append_logger( self , logger , key=None ):
|
|
348
|
+
if key is None :
|
|
349
|
+
key = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for x in range(40))
|
|
350
|
+
|
|
351
|
+
self.__log[key] = logger
|
|
352
|
+
|
|
353
|
+
if self.__default_logger is None :
|
|
354
|
+
self.__default_logger = key
|
|
355
|
+
|
|
356
|
+
return key
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def enable_log( self , log_X=True , log_V=False , sim_time=None , log_max_size=0 ):
|
|
360
|
+
"""
|
|
361
|
+
Eanble the X and V logging:
|
|
362
|
+
|
|
363
|
+
:param log_X=True: log the positions
|
|
364
|
+
:param log_V=False: log the velocity
|
|
365
|
+
:param log_max_size: max size of the log queue
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
if len( self.__log ) == 0 :
|
|
369
|
+
logg = log.Logger( self , log_max_size=log_max_size , log_X=log_X , log_V=log_V , sim_time=sim_time )
|
|
370
|
+
self.append_logger( logg )
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def log(self):
|
|
374
|
+
"""
|
|
375
|
+
| If the log is enabled, save the current status in the log queue.
|
|
376
|
+
| The last element of the queue will be removed if we reach the max allowed size
|
|
377
|
+
"""
|
|
378
|
+
for key in self.__log.keys() :
|
|
379
|
+
self.__log[key].log()
|
|
380
|
+
|
|
381
|
+
def close_log(self):
|
|
382
|
+
"""
|
|
383
|
+
This function must be called after the end of the simulation for closing the log procedure.
|
|
384
|
+
"""
|
|
385
|
+
for key in self.__log.keys() :
|
|
386
|
+
self.__log[key].close_log()
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def get_log_max_size( self ):
|
|
390
|
+
return self.__log[self.__default_logger].log_max_size
|
|
391
|
+
|
|
392
|
+
def set_log_max_size( self , log_max_size ):
|
|
393
|
+
self.__log[self.__default_logger].log_max_size = log_max_size
|
|
394
|
+
|
|
395
|
+
log_max_size = property( get_log_max_size , set_log_max_size , doc="set and get the max allowed size of the log")
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def get_log_array( self , i , log_X=True , log_V=False ):
|
|
400
|
+
return self.__log[self.__default_logger].get_log_array( i , log_X , log_V )
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def read_log_array( self , i , ta , log_X=True , log_V=False ):
|
|
404
|
+
return self.__log[self.__default_logger].read_log_array( i , ta , log_X , log_V )
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def get_log_indices_segments( self , full=False ):
|
|
408
|
+
return self.__log[self.__default_logger].get_log_indices_segments( full )
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def set_default_logger( self , key ):
|
|
412
|
+
|
|
413
|
+
if key not in self.__log.keys() :
|
|
414
|
+
raise ValueError("A log named %s do not exits" % key )
|
|
415
|
+
|
|
416
|
+
self.__default_logger = key
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def get_log_size(self):
|
|
421
|
+
return self.__log[self.__default_logger].log_size
|
|
422
|
+
|
|
423
|
+
log_size = property( get_log_size )
|
|
424
|
+
|
|
425
|
+
def get_log_X_enabled(self):
|
|
426
|
+
if not self.log_enabled :
|
|
427
|
+
return False
|
|
428
|
+
else :
|
|
429
|
+
return self.__log[self.__default_logger].log_X_enabled
|
|
430
|
+
|
|
431
|
+
def get_log_V_enabled(self):
|
|
432
|
+
if not self.log_enabled :
|
|
433
|
+
return False
|
|
434
|
+
else :
|
|
435
|
+
return self.__log[self.__default_logger].log_V_enabled
|
|
436
|
+
|
|
437
|
+
def get_log_enabled(self):
|
|
438
|
+
return len( self.__log ) > 0
|
|
439
|
+
|
|
440
|
+
log_V_enabled = property( get_log_V_enabled , doc="return true if the logging of the position is enabled")
|
|
441
|
+
log_X_enabled = property( get_log_X_enabled , doc="return true if the logging of the velocity is enabled")
|
|
442
|
+
|
|
443
|
+
log_enabled = property( get_log_enabled , doc="return true if the logging of position or velocity is enabled")
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def jump( self , indx ):
|
|
447
|
+
pass
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def set_unit( self , u ):
|
|
451
|
+
self.__unit = u
|
|
452
|
+
|
|
453
|
+
def get_unit(self):
|
|
454
|
+
return self.__unit
|
|
455
|
+
|
|
456
|
+
unit = property( get_unit , set_unit , doc="set the unit length")
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def set_mass_unit( self , u ):
|
|
460
|
+
self.__mass_unit = u
|
|
461
|
+
|
|
462
|
+
def get_mass_unit(self):
|
|
463
|
+
return self.__mass_unit
|
|
464
|
+
|
|
465
|
+
mass_unit = property( get_mass_unit , set_mass_unit , doc="set the unit mass" )
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def update_centre_of_mass(self):
|
|
469
|
+
"""
|
|
470
|
+
Compute and return the center of mass
|
|
471
|
+
"""
|
|
472
|
+
self.__centre_mass = np.sum( self.__X * self.__mass , axis=0 ) / self.dtype( self.__size )
|
|
473
|
+
return self.__centre_mass
|
|
474
|
+
|
|
475
|
+
def centre_of_mass(self):
|
|
476
|
+
"""
|
|
477
|
+
Return the stored center of mass.
|
|
478
|
+
|
|
479
|
+
.. note::
|
|
480
|
+
|
|
481
|
+
this function don't compute the center of mass, but simply return the stored value.
|
|
482
|
+
"""
|
|
483
|
+
return self.__centre_mass
|
|
484
|
+
|
|
485
|
+
def get_dim(self):
|
|
486
|
+
return self.__dim
|
|
487
|
+
|
|
488
|
+
def get_size( self ):
|
|
489
|
+
return self.__size
|
|
490
|
+
|
|
491
|
+
dim = property( get_dim , doc="get the dim of the set" )
|
|
492
|
+
|
|
493
|
+
size = property( get_size , doc="get the size of the set" )
|
|
494
|
+
|
|
495
|
+
def add_clusters( self , Cs , n ):
|
|
496
|
+
i = 0
|
|
497
|
+
for c in Cs:
|
|
498
|
+
self.__X[n[i]:n[i]+c.shape[0]] = c
|
|
499
|
+
i = i + 1
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
# PyParticles : Particles simulation in python
|
|
3
|
+
# Copyright (C) 2012 Simone Riva
|
|
4
|
+
#
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pyparticles.pset.boundary as bd
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PeriodicBoundary( bd.Boundary ):
|
|
23
|
+
|
|
24
|
+
def __init__( self , bound=(-1,1) , dim=3 ):
|
|
25
|
+
self.set_boundary( bound , dim )
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def boundary( self , p_set ):
|
|
29
|
+
for i in range( self.dim ) :
|
|
30
|
+
delta = self.bound[i,1] - self.bound[i,0]
|
|
31
|
+
|
|
32
|
+
b_mi = p_set.X[:,i] < self.bound[i,0]
|
|
33
|
+
b_mx = p_set.X[:,i] > self.bound[i,1]
|
|
34
|
+
|
|
35
|
+
p_set.X[b_mi,i] = p_set.X[b_mi,i] + delta
|
|
36
|
+
p_set.X[b_mx,i] = p_set.X[b_mx,i] - delta
|