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,451 @@
1
+ # PyParticles : Particles simulation in python
2
+ # Copyright (C) 2012 Simone Riva simone.rva {at} gmail {dot} com
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
+ from pyparticles.geometry.intersection import box_intersects_sphere
19
+ from pyparticles.geometry.dist import distance
20
+
21
+ import multiprocessing as mpr
22
+
23
+ import numpy as np
24
+
25
+ from collections import deque
26
+
27
+
28
+ class TreeElement( object ):
29
+ """
30
+ The element of a tree node
31
+ """
32
+ def __init__( self ):
33
+
34
+ self.__particle = None
35
+
36
+ self.__ref_vertex = np.zeros((3))
37
+ self.__edge_len = 0.0
38
+
39
+ self.__M = 0.0
40
+ self.__centre_of_mass = np.zeros((3))
41
+
42
+ self.__part_cnt = 0
43
+
44
+ self.__tree = None
45
+
46
+ self.__left = np.int8( np.array([ 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ]) )
47
+ self.__right = np.int8( np.array([ 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ]) )
48
+
49
+ self.__near = np.int8( np.array([ 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 ]) )
50
+ self.__far = np.int8( np.array([ 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 ]) )
51
+
52
+ self.__up = np.int8( np.array([ 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 ]) )
53
+ self.__down = np.int8( np.array([ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 ]) )
54
+
55
+
56
+
57
+ def get_particle( self ) :
58
+ return self.__particle
59
+
60
+ particle = property( get_particle , doc="Get the particle index of the tree element" )
61
+
62
+
63
+ def get_min_vertex( self ):
64
+ return self.__ref_vertex
65
+
66
+ min_vertex = property( get_min_vertex , doc="get the minimal vertex of the cube" )
67
+
68
+
69
+ def get_max_vertex( self ):
70
+ return self.__ref_vertex + np.array( [ self.__edge_len , self.__edge_len , self.__edge_len ] )
71
+
72
+ max_vertex = property( get_max_vertex , doc="get the maximal vertex of the cube" )
73
+
74
+
75
+ def getM(self):
76
+ return self.__M
77
+
78
+ M = property( getM , doc="getter: return the total mass of the current element ")
79
+
80
+
81
+ def get_centre_of_mass( self ):
82
+ return self.__centre_of_mass
83
+
84
+ centre_of_mass = property( get_centre_of_mass , doc="return the centre of mass of the particle" )
85
+
86
+
87
+ def set_local_boundary( self , ref_vertex , edge_len ) :
88
+ self.__ref_vertex[:] = ref_vertex
89
+ self.__edge_len = edge_len
90
+
91
+
92
+ def add_sub_trees( self ):
93
+ self.__tree = list( TreeElement() for i in range(8) )
94
+
95
+ ## I - I
96
+ self.__tree[0].set_local_boundary( self.__ref_vertex , self.__edge_len / 2.0 )
97
+
98
+ d = np.array([ self.right[0] , 0.0 , 0.0 ]) * self.__edge_len
99
+ self.__tree[1].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
100
+
101
+ d = np.array([ self.right[0] , self.far[0] , 0.0 ]) * self.__edge_len
102
+ self.__tree[2].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
103
+
104
+ d = np.array([ self.left[0] , self.far[0] , 0.0 ]) * self.__edge_len
105
+ self.__tree[3].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
106
+
107
+ ## II
108
+ d = np.array([ self.left[0] , self.near[0] , self.up[0] ]) * self.__edge_len
109
+ self.__tree[4].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
110
+
111
+ d = np.array([ self.right[0] , self.near[0] , self.up[0] ]) * self.__edge_len
112
+ self.__tree[5].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
113
+
114
+ d = np.array([ self.right[0] , self.far[0] , self.up[0] ]) * self.__edge_len
115
+ self.__tree[6].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
116
+
117
+ d = np.array([ self.left[0] , self.far[0] , self.up[0] ]) * self.__edge_len
118
+ self.__tree[7].set_local_boundary( self.__ref_vertex + d , self.__edge_len / 2.0 )
119
+
120
+
121
+ def is_in( self , coord ):
122
+ a = coord >= self.__ref_vertex
123
+ b = coord < ( self.__ref_vertex + self.__edge_len )
124
+
125
+ return np.all( np.logical_and( a , b ) )
126
+
127
+
128
+ def insert_particle_mp( self , pset , i ):
129
+ pass
130
+
131
+
132
+ def insert_particle( self , pset , i ) :
133
+ if self.particle == None and self.__tree == None :
134
+ self.__particle = i
135
+ self.__M = pset.M[i]
136
+ self.__centre_of_mass = pset.X[i,:]
137
+ self.__part_cnt = 1
138
+ return
139
+
140
+ elif self.particle != None and self.__tree == None :
141
+ self.add_sub_trees()
142
+
143
+ elif self.particle != None and self.__tree != None :
144
+ pass ## it's only for testing the coherence of the tree structure
145
+
146
+ else :
147
+ raise
148
+
149
+ # update mass
150
+ self.__M += pset.M[i]
151
+
152
+ # update centre of mass
153
+ self.__centre_of_mass = ( self.__centre_of_mass * self.__part_cnt + pset.X[i,:] ) / ( self.__part_cnt + 1 )
154
+ self.__part_cnt += 1
155
+
156
+ # Old version, a bit slower.
157
+ #j = 0
158
+ #jj = 0
159
+ #for st in self.__tree :
160
+ # if st.is_in( pset.X[i,:] ) :
161
+ # jj = j
162
+ # st.insert_particle( pset , i )
163
+ # break
164
+ # j += 1
165
+
166
+ #return
167
+
168
+ indx = np.int8( np.array( [0,1,2,3,4,5,6,7] ) )
169
+
170
+ if pset.X[i,0] >= self.__ref_vertex[0] and pset.X[i,0] < self.__ref_vertex[0] + self.__edge_len/2.0 :
171
+ # Left
172
+ indx[:] = indx * self.__left
173
+ elif pset.X[i,0] >= self.__ref_vertex[0] + self.__edge_len/2.0 and pset.X[i,0] < self.__ref_vertex[0] + self.__edge_len :
174
+ # Right
175
+ indx[:] = indx * self.__right
176
+
177
+
178
+ if pset.X[i,1] >= self.__ref_vertex[1] and pset.X[i,1] < self.__ref_vertex[1] + self.__edge_len/2.0 :
179
+ # near
180
+ indx[:] = indx * self.__near
181
+ elif pset.X[i,1] >= self.__ref_vertex[1] + self.__edge_len/2.0 and pset.X[i,1] < self.__ref_vertex[1] + self.__edge_len :
182
+ # far
183
+ indx[:] = indx * self.__far
184
+
185
+
186
+ if pset.X[i,2] >= self.__ref_vertex[2] and pset.X[i,2] < self.__ref_vertex[2] + self.__edge_len/2.0 :
187
+ # down
188
+ indx[:] = indx * self.__down
189
+ elif pset.X[i,2] >= self.__ref_vertex[2] + self.__edge_len/2.0 and pset.X[i,2] < self.__ref_vertex[2] + self.__edge_len :
190
+ # up
191
+ indx[:] = indx * self.__up
192
+
193
+ ix = np.sum( indx )
194
+ self.__tree[ix].insert_particle( pset , i )
195
+
196
+ #print ( indx )
197
+ #print("")
198
+ #print ( "ix %d" % ix )
199
+ #print ( "jj %d" % jj )
200
+ #print ( "----------" )
201
+
202
+ #if jj != ix :
203
+ # print ("Fatal!!!!")
204
+ # exit()
205
+ #
206
+ return
207
+
208
+
209
+ def search_neighbour( self , cand_queue , res_list , pset , X , r ):
210
+ """
211
+ Search the elements included in the volume centred in *X* with the radius *r* and append the results in the list *res_list*.
212
+ *res_list* contains the indicies of the particles included in the the sphere.
213
+ """
214
+ while len(cand_queue) :
215
+ tree = cand_queue.pop()
216
+
217
+ if distance( pset.X[tree.particle,:] , X ) <= r :
218
+ res_list.append( tree.particle )
219
+
220
+ if tree.__tree == None :
221
+ continue
222
+
223
+ for t in tree.__tree:
224
+ if t.particle != None and box_intersects_sphere( t.min_vertex , t.max_vertex , X , r ) :
225
+ cand_queue.append( t )
226
+
227
+
228
+ def print_tree( self , pset , d=1 ):
229
+ """
230
+ Print the structure of the tree and return the maximal depth
231
+
232
+ Args:
233
+ pset: the particles set
234
+ d: current depth (1 for the first node)
235
+ """
236
+ if self.__particle == None :
237
+ return
238
+
239
+ vrtx = tuple(i for i in self.__ref_vertex)
240
+ cm = tuple(i for i in self.__centre_of_mass)
241
+ coord = tuple(i for i in pset.X[self.__particle,:] )
242
+
243
+ spc = " +"
244
+
245
+ print( "" )
246
+ print( "%s -------------------- " % ( spc*d ) )
247
+ print( "%s depth : %d " % ( spc*d , d ) )
248
+ print( "%s part indx: %d " % ( spc*d , self.__particle ) )
249
+ print( "%s part coord: %s " % ( spc*d , coord ) )
250
+ print( "%s vertex: %s " % ( spc*d , vrtx ) )
251
+ print( "%s edge: %s " % ( spc*d , self.__edge_len ) )
252
+ print( "%s centre of mass: %s " % ( spc*d , cm ) )
253
+
254
+ mx = d
255
+ if self.__tree != None:
256
+ for tr in self.__tree :
257
+ mx = max ( tr.print_tree( pset , d+1 ) , mx )
258
+
259
+ return mx
260
+
261
+
262
+ def depth( self , d = 1 ):
263
+ """
264
+ Compute and returns the maximal depth of the octree
265
+ """
266
+ mx = d
267
+ if self.__tree != None:
268
+ for tr in self.__tree :
269
+ mx = max ( tr.depth( d+1 ) , mx )
270
+
271
+ return mx
272
+
273
+
274
+ def get_up(self):
275
+ """
276
+ Z axis
277
+ """
278
+ return ( 0.5 , 1.0 )
279
+
280
+ def get_down(self):
281
+ return ( 0.0 , 0.5 )
282
+
283
+ def get_left(self):
284
+ return ( 0.0 , 0.5 )
285
+
286
+ def get_right(self):
287
+ return ( 0.5 , 1.0 )
288
+
289
+ def get_near(self):
290
+ return ( 0.0 , 0.5 )
291
+
292
+ def get_far(self):
293
+ return ( 0.5 , 1.0 )
294
+
295
+ up = property( get_up , doc="relative domanin for the up 'sub-space' " )
296
+ down = property( get_down , doc="relative domanin for the down 'sub-space' " )
297
+ left = property( get_left , doc="relative domanin for the left 'sub-space' " )
298
+ right = property( get_right , doc="relative domanin for the right 'sub-space' " )
299
+ near = property( get_near , doc="relative domanin for the near 'sub-space' " )
300
+ far = property( get_far , doc="relative domanin for the far 'sub-space' " )
301
+
302
+
303
+
304
+ class OcTree ( object ):
305
+ """
306
+ |OcTree particles container class
307
+ """
308
+ def __init__( self ):
309
+ self.__tree = None
310
+ self.__pset = None
311
+ self.__ref_vertex = np.zeros((3))
312
+ self.__edge_len = 1.0
313
+
314
+ def set_global_boundary( self ,
315
+ ref_vertex = np.array([ 0.0 , 0.0 , 0.0 ]) ,
316
+ edge_len = 1.0 ) :
317
+
318
+ """
319
+ Define the size of the octree cube
320
+
321
+ ========== =================================
322
+ Arguments
323
+ ========== =================================
324
+ ref_vertex the ( down , near , left ) vertex
325
+ edge_len leght of the edge
326
+ ========== =================================
327
+ """
328
+
329
+ self.__ref_vertex[:] = ref_vertex
330
+ self.__edge_len = edge_len
331
+
332
+
333
+ def get_centre_of_mass( self ):
334
+ return self.__tree.centre_of_mass
335
+
336
+ centre_of_mass = property( get_centre_of_mass , doc="return the centre of mass of the particles set" )
337
+
338
+
339
+ def search_neighbour( self , X , r ):
340
+ """
341
+ return an array containing the indecies of the the particles included in the sheric region centred in *X* with a radius *r*
342
+ """
343
+
344
+ res_list = []
345
+
346
+ if self.__tree == None :
347
+ return np.array(res_list)
348
+
349
+ if not self.__tree.is_in( X ):
350
+ return np.array(res_list)
351
+
352
+ cq = deque( [ self.__tree ] )
353
+
354
+ self.__tree.search_neighbour( cq , res_list , self.__pset , X , r )
355
+
356
+ return np.array(res_list)
357
+
358
+
359
+ def __build_tree_mp( self , pset ) :
360
+ """
361
+ Build the octree with the given particles set with a parrallel processig procedure
362
+
363
+ Arguments:
364
+ ==== ============================================
365
+ pset a ParticlesSet object used to build the tree
366
+ ==== ============================================
367
+ """
368
+
369
+ if self.__tree == None :
370
+ self.__tree = TreeElement()
371
+ else :
372
+ del self.__tree
373
+ self.__tree = TreeElement()
374
+
375
+ self.__tree.set_local_boundary( self.__ref_vertex , self.__edge_len )
376
+
377
+ self.__pset = pset
378
+
379
+ cpu = mpr.cpu_count()
380
+ jobs_queue = mpr.Queue()
381
+
382
+ parent_conn = list( None for i in range(cpu) )
383
+ child_conn = list( None for i in range(cpu) )
384
+
385
+ procs = list( None for i in range(cpu) )
386
+
387
+ for i in range( cpu ) :
388
+ ( parent_conn[i] , child_conn[i] ) = mpr.Pipe()
389
+ procs[i] = mpr.Process(target=self.__build_tree_process , args=( jobs_queue , child_conn[i] ) )
390
+ parent_conn[i].send( [ pset , self.__tree ] )
391
+
392
+ for i in range( pset.size ):
393
+ jobs_queue.put( i )
394
+
395
+ for i in range( cpu ) :
396
+ procs[i].start()
397
+
398
+ for p in procs :
399
+ p.join()
400
+
401
+
402
+ def __build_tree_process( self , queue , child_conn ) :
403
+
404
+ t_args = child_conn.recv()
405
+ pset = t_args[0]
406
+ tree = t_args[1]
407
+
408
+ # get the first job.
409
+
410
+ flag = True
411
+ while flag :
412
+ if queue.empty() :
413
+ flag = False
414
+ continue
415
+ i = queue.get()
416
+ print( i )
417
+
418
+
419
+ def build_tree( self , pset ) :
420
+ """
421
+ Build the octree with the given particles set
422
+
423
+ ========= ============================================
424
+ Arguments
425
+ ========= ============================================
426
+ pset a ParticlesSet object used to build the tree
427
+ ========= ============================================
428
+ """
429
+
430
+ if self.__tree == None :
431
+ self.__tree = TreeElement()
432
+ else :
433
+ del self.__tree
434
+ self.__tree = TreeElement()
435
+
436
+ self.__tree.set_local_boundary( self.__ref_vertex , self.__edge_len )
437
+
438
+ self.__pset = pset
439
+
440
+ for i in range( pset.size ):
441
+ self.__tree.insert_particle( pset , i )
442
+
443
+
444
+ def print_tree( self ):
445
+ mx = self.__tree.print_tree( self.__pset , 1 )
446
+
447
+ print("")
448
+ print("Max depth: %d " % mx )
449
+ print("")
450
+
451
+