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,174 @@
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
+ import pyparticles.pset.opencl_context as occ
22
+
23
+ try:
24
+ import pyopencl as cl
25
+ import pyopencl.array as cla
26
+ except:
27
+ ___foo = 0
28
+
29
+
30
+ class Damping( fr.Force ) :
31
+ r"""
32
+ Compute the damping forces, the damping is a force that react proportionally to the velocity
33
+
34
+ The force is given the equation:
35
+
36
+ .. math::
37
+
38
+ F_i = -C\dot{X}
39
+
40
+ Constructor
41
+
42
+ :param size: the number of particles in the system
43
+ :param dim: the dimension of the system
44
+ :param m: a vector containig the masses
45
+ :param Const: the damping factor
46
+ """
47
+ def __init__(self , size , dim=3 , m=None , Consts=1.0 ):
48
+
49
+ self.__dim = dim
50
+ self.__size = size
51
+
52
+ self.__C = np.zeros( ( size , 1 ) )
53
+ self.__C[:] = Consts
54
+
55
+ self.__A = np.zeros( ( size , dim ) )
56
+ self.__F = np.zeros( ( size , dim ) )
57
+
58
+ self.__M = np.zeros( ( size , 1 ) )
59
+ if m != None :
60
+ self.set_masses( m )
61
+
62
+
63
+
64
+ def set_masses( self , m ):
65
+ self.__M[:] = m
66
+
67
+
68
+ def update_force( self , pset ):
69
+
70
+ self.__F[:] = -pset.V[:] * self.__C[:]
71
+ self.__A = self.__F[:] / self.__M
72
+
73
+ return self.__A
74
+
75
+
76
+ def getA(self):
77
+ return self.__A
78
+
79
+ A = property( getA )
80
+
81
+
82
+ def getF(self):
83
+ return self.__A * self.__M[:,0]
84
+
85
+ F = property( getF )
86
+
87
+
88
+ class DampingOCL( fr.Force ) :
89
+ r"""
90
+ Compute the damping forces, the damping is a force that react proportionally to the velocity
91
+
92
+ The force is given the equation:
93
+
94
+ .. math::
95
+
96
+ F_i = -C\dot{X}
97
+
98
+ Constructor
99
+
100
+ :param size: the number of particles in the system
101
+ :param dim: the dimension of the system
102
+ :param m: a vector containig the masses
103
+ :param Const: the damping factor
104
+ """
105
+ def __init__(self , size , dim=3 , m=None , Consts=1.0 , ocl_context=None ):
106
+
107
+ self.__dim = np.int( dim )
108
+ self.__size = np.int( size )
109
+
110
+ if ocl_context == None :
111
+ self.__occ = occ.OpenCLcontext( size , dim , ( occ.OCLC_V | occ.OCLC_A | occ.OCLC_M ) )
112
+ else :
113
+ self.__occ = ocl_context
114
+
115
+ self.__dtype = self.__occ.dtype
116
+
117
+ self.__K = self.__occ.dtype( Consts )
118
+
119
+ self.__A = np.zeros( ( size , dim ) , dtype=self.__occ.dtype )
120
+ self.__F = np.zeros( ( size , dim ) , dtype=self.__occ.dtype )
121
+
122
+ if m != None :
123
+ self.set_masses( m )
124
+
125
+ self.__init_prog_cl()
126
+
127
+
128
+ def __init_prog_cl(self):
129
+ self.__damping_prg = """
130
+ __kernel void damping(__global const float *V ,
131
+ __global const float *M ,
132
+ float K ,
133
+ __global float *A )
134
+ {
135
+ int i = get_global_id(0) ;
136
+
137
+ A[3*i] = ( K * V[3*i] ) / M[i] ;
138
+ A[3*i+1] = ( K * V[3*i+1] ) / M[i] ;
139
+ A[3*i+2] = ( K * V[3*i+2] ) / M[i] ;
140
+ }
141
+ """
142
+
143
+ self.__cl_program = cl.Program( self.__occ.CL_context , self.__damping_prg ).build()
144
+
145
+
146
+ def set_masses( self , m ):
147
+ self.__occ.M_cla.set( self.__dtype( m ) , queue=self.__occ.CL_queue )
148
+
149
+
150
+ def update_force( self , pset ):
151
+
152
+ self.__occ.V_cla.set( self.__dtype( pset.V ) , queue=self.__occ.CL_queue )
153
+
154
+ self.__cl_program.damping( self.__occ.CL_queue , ( self.__size , ) , None ,
155
+ self.__occ.V_cla.data ,
156
+ self.__occ.M_cla.data ,
157
+ self.__K ,
158
+ self.__occ.A_cla.data )
159
+
160
+ self.__occ.A_cla.get( self.__occ.CL_queue , self.__A )
161
+
162
+ return self.__A
163
+
164
+
165
+ def getA(self):
166
+ return self.__A
167
+
168
+ A = property( getA )
169
+
170
+
171
+ def getF(self):
172
+ return self.__A * self.__M[:,0]
173
+
174
+ F = property( getF )
@@ -0,0 +1,167 @@
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
+ import numpy as np
10
+
11
+ import pyparticles.forces.force as fr
12
+ import pyparticles.pset.opencl_context as occ
13
+
14
+ try:
15
+ import pyopencl as cl
16
+ except ImportError:
17
+ cl = None
18
+
19
+
20
+ class Drag(fr.Force):
21
+ """Quadratic drag force."""
22
+
23
+ def __init__(self, size, dim=3, m=None, Consts=1.0):
24
+ self.__dim = int(dim)
25
+ self.__size = int(size)
26
+ self.__G = np.zeros((size, 1))
27
+ self.__G[:] = Consts
28
+ self.__A = np.zeros((size, dim))
29
+ self.__F = np.zeros((size, dim))
30
+ self.__V = np.zeros((size, 1))
31
+ self.__M = np.zeros((size, 1))
32
+
33
+ if m is not None:
34
+ self.set_masses(m)
35
+
36
+ def set_masses(self, m):
37
+ self.__M[:] = m
38
+
39
+ def update_force(self, pset):
40
+ self.__V[:, 0] = np.sqrt(np.sum(pset.V**2, axis=1))
41
+ self.__F[:] = -0.5 * self.__V * pset.V * self.__G
42
+ self.__A[:] = self.__F / self.__M
43
+ return self.__A
44
+
45
+ def getA(self):
46
+ return self.__A
47
+
48
+ A = property(getA)
49
+
50
+ def getF(self):
51
+ return self.__A * self.__M
52
+
53
+ F = property(getF)
54
+
55
+
56
+ class DragOCL(fr.Force):
57
+ """OpenCL implementation of 3-D quadratic drag."""
58
+
59
+ def __init__(self, size, dim=3, m=None, Consts=1.0, ocl_context=None):
60
+ if cl is None:
61
+ raise RuntimeError("PyOpenCL is required for DragOCL")
62
+ if int(dim) != 3:
63
+ raise ValueError("DragOCL currently supports only 3 dimensions")
64
+
65
+ self.__dim = int(dim)
66
+ self.__size = int(size)
67
+
68
+ if ocl_context is None:
69
+ self.__occ = occ.OpenCLcontext(
70
+ size,
71
+ dim,
72
+ occ.OCLC_V | occ.OCLC_A | occ.OCLC_M,
73
+ )
74
+ else:
75
+ self.__occ = ocl_context
76
+
77
+ self.__dtype = self.__occ.dtype
78
+ self.__K = self.__dtype(Consts)
79
+ self.__A = np.zeros((size, dim), dtype=self.__dtype)
80
+ self.__M = np.zeros((size, 1), dtype=self.__dtype)
81
+
82
+ self.__init_prog_cl()
83
+ if m is not None:
84
+ self.set_masses(m)
85
+
86
+ def __init_prog_cl(self):
87
+ source = r"""
88
+ __kernel void drag(
89
+ __global const float *V,
90
+ __global const float *M,
91
+ float K,
92
+ int accumulate,
93
+ __global float *A)
94
+ {
95
+ int i = get_global_id(0);
96
+ int i0 = 3*i;
97
+ int i1 = i0 + 1;
98
+ int i2 = i0 + 2;
99
+
100
+ float speed = sqrt(
101
+ V[i0]*V[i0] + V[i1]*V[i1] + V[i2]*V[i2]
102
+ );
103
+
104
+ float ax = (-0.5f * K * speed * V[i0]) / M[i];
105
+ float ay = (-0.5f * K * speed * V[i1]) / M[i];
106
+ float az = (-0.5f * K * speed * V[i2]) / M[i];
107
+
108
+ if (accumulate)
109
+ {
110
+ A[i0] += ax;
111
+ A[i1] += ay;
112
+ A[i2] += az;
113
+ }
114
+ else
115
+ {
116
+ A[i0] = ax;
117
+ A[i1] = ay;
118
+ A[i2] = az;
119
+ }
120
+ }
121
+ """
122
+ self.__cl_program = cl.Program(self.__occ.CL_context, source).build()
123
+ self.__drag_kernel = cl.Kernel(self.__cl_program, "drag")
124
+
125
+ def set_masses(self, m):
126
+ self.__M[:] = np.asarray(m, dtype=self.__dtype)
127
+ self.__occ.set_from_host("M", self.__M)
128
+
129
+ def update_force_device(self, pset, accumulate=False, host_authoritative=False):
130
+ if host_authoritative:
131
+ self.__occ.mark_host_modified("V")
132
+ self.__occ.sync_to_device("V", pset.V)
133
+
134
+ self.__drag_kernel(
135
+ self.__occ.CL_queue,
136
+ (self.__size,),
137
+ None,
138
+ self.__occ.V_cla.data,
139
+ self.__occ.M_cla.data,
140
+ self.__K,
141
+ np.int32(bool(accumulate)),
142
+ self.__occ.A_cla.data,
143
+ )
144
+ self.__occ.mark_device_modified("A")
145
+ return self.__occ.A_cla
146
+
147
+ def update_force(self, pset):
148
+ self.update_force_device(pset, accumulate=False, host_authoritative=True)
149
+ self.__occ.sync_to_host("A", self.__A)
150
+ return self.__A
151
+
152
+ def getA(self):
153
+ return self.__A
154
+
155
+ A = property(getA)
156
+
157
+ def getF(self):
158
+ # Keep the legacy host property useful even after a device-only update.
159
+ self.__occ.sync_to_host("A", self.__A)
160
+ return self.__A * self.__M
161
+
162
+ F = property(getF)
163
+
164
+ def get_ocl_context(self):
165
+ return self.__occ
166
+
167
+ ocl_context = property(get_ocl_context)
@@ -0,0 +1,105 @@
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
+ import scipy.spatial.distance as dist
19
+
20
+ import pyparticles.forces.force as fr
21
+
22
+ class Electromagnetic( fr.Force ) :
23
+ r"""
24
+ Compute the electromagnetic force of a self-interacting particles system according to the Lorenz formulation.
25
+
26
+
27
+
28
+ Not yet tested.
29
+ """
30
+ def __init__( self , size , dim=3 , m=None , Consts=1.0 ):
31
+
32
+ self.__dim = dim
33
+ self.__size = size
34
+
35
+ self.__Ke = Consts[0]
36
+ self.__Km = Consts[1]
37
+
38
+ self.__Am = np.zeros( ( size , dim ) )
39
+ self.__Ae = np.zeros( ( size , dim ) )
40
+
41
+ self.__Fe = np.zeros( ( size , size ) )
42
+ self.__Fm = np.zeros( ( size , size ) )
43
+
44
+ self.__V = np.zeros( ( size , size ) )
45
+ self.__D = np.zeros( ( size , size ) )
46
+ self.__Q = np.zeros( ( size , size ) )
47
+ self.__M = np.zeros( ( size , 1 ) )
48
+
49
+ self.__r = np.zeros( ( size , dim ) )
50
+
51
+ self.__Cr = np.zeros( ( size , dim ) )
52
+
53
+ if m != None :
54
+ self.set_masses( m )
55
+
56
+ def set_masses( self , m ):
57
+ self.__M[:] = m
58
+
59
+ def set_charges( self , q ):
60
+ self.__Q[:,:] = q
61
+ self.__Q[:,:] = self.__Q * self.__Q.T
62
+
63
+ def update_force( self , p_set ):
64
+ self.__D[:] = dist.squareform( dist.pdist( p_set.X , 'euclidean' ) )
65
+
66
+ self.__Fe[:] = self.__Ke * self.__Q[:] / ( ( self.__D[:] ) ** 3.0 )
67
+ self.__Fm[:] = self.__Km * self.__Q[:] / ( ( self.__D[:] ) ** 2.0 )
68
+
69
+ np.fill_diagonal( self.__Fe , 0.0 )
70
+ np.fill_diagonal( self.__Fm , 0.0 )
71
+
72
+ for i in range( self.__dim ):
73
+ self.__V[:,:] = p_set.X[:,i]
74
+ self.__V[:,:] = ( self.__V[:,:].T - p_set.X[:,i] ).T
75
+
76
+ self.__Ae[:,i] = np.sum( self.__Fe * self.__V[:,:] , 0 )
77
+
78
+ r = self.__r
79
+ for j in range( self.__size ) :
80
+ r[:] = p_set.X[j,:] - p_set.X[:]
81
+
82
+ r[:] = (r.T / np.sqrt( np.sum(r**2,1))).T
83
+ r[j,:] = 0.0
84
+
85
+ r[:] = np.cross( p_set.V[:] , r[:] )
86
+ r[:] = np.cross( p_set.V[j,:] , r[:] )
87
+
88
+ self.__Am[j,:] = np.sum( self.__Fm[:,j].T * r[:] , 0 ).T / self.__M[j]
89
+
90
+
91
+ #print( self.__X )
92
+ self.__A[:] = self.__Ae + self.__Am
93
+
94
+ return self.__A
95
+
96
+ def getA(self):
97
+ return self.__A
98
+
99
+ A = property( getA )
100
+
101
+
102
+ def getF(self):
103
+ return self.__A * self.__M
104
+
105
+ F = property( getF )
@@ -0,0 +1,95 @@
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 random
18
+
19
+ import numpy as np
20
+
21
+ import pyparticles.forces.force as fr
22
+
23
+
24
+ class ElectromagneticField(fr.Force):
25
+ r"""
26
+ Electromagnetic force for non-self-interacting charged particles.
27
+
28
+ .. math::
29
+
30
+ \mathbf{F} = q(\mathbf{E} + \mathbf{v} \times \mathbf{B})
31
+ """
32
+
33
+ def __init__(self, size, dim=3, m=None, q=None, Consts=1.0):
34
+ self.__dim = dim
35
+ self.__size = size
36
+
37
+ self.__A = np.zeros((size, dim))
38
+ self.__E = np.zeros((size, dim))
39
+ self.__B = np.zeros((size, dim))
40
+ self.__Fe = np.zeros((size, dim))
41
+ self.__Fm = np.zeros((size, dim))
42
+ self.__M = np.zeros((size, 1))
43
+ self.__Q = np.zeros((size, 1))
44
+
45
+ if m is not None:
46
+ self.set_masses(m)
47
+ if q is not None:
48
+ self.set_charges(q)
49
+
50
+ self.__el_fields = {}
51
+ self.__ma_fields = {}
52
+
53
+ def set_masses(self, m):
54
+ self.__M[:] = m
55
+
56
+ def set_charges(self, q):
57
+ self.__Q[:] = q
58
+
59
+ def append_electric_field(self, ef, key=None):
60
+ if key is None:
61
+ key = str(random.randint(0, 2**64))
62
+ self.__el_fields[key] = ef
63
+ return key
64
+
65
+ def append_magnetic_field(self, bf, key=None):
66
+ if key is None:
67
+ key = str(random.randint(0, 2**64))
68
+ self.__ma_fields[key] = bf
69
+ return key
70
+
71
+ def update_force(self, pset):
72
+ self.__Fe[:] = 0.0
73
+ self.__Fm[:] = 0.0
74
+
75
+ for field in self.__el_fields.values():
76
+ field(self.__E, pset.X)
77
+ self.__Fe += self.__Q * self.__E
78
+
79
+ for field in self.__ma_fields.values():
80
+ field(self.__B, pset.X)
81
+ self.__Fm += self.__Q * np.cross(pset.V, self.__B)
82
+
83
+ self.__Fe += self.__Fm
84
+ self.__A[:] = self.__Fe / self.__M
85
+ return self.__A
86
+
87
+ def getA(self):
88
+ return self.__A
89
+
90
+ A = property(getA)
91
+
92
+ def getF(self):
93
+ return self.__Fe
94
+
95
+ F = property(getF)
@@ -0,0 +1,72 @@
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
+ import scipy.spatial.distance as dist
19
+
20
+ import pyparticles.forces.force as fr
21
+
22
+
23
+ class Electrostatic(fr.Force):
24
+ r"""Compute electrostatic force using Coulomb's law."""
25
+
26
+ def __init__(self, size, dim=3, m=None, q=None, Consts=1.0):
27
+ self.__dim = dim
28
+ self.__size = size
29
+ self.__K = Consts
30
+ self.__A = np.zeros((size, dim))
31
+ self.__Fm = np.zeros((size, size))
32
+ self.__V = np.zeros((size, size))
33
+ self.__D = np.zeros((size, size))
34
+ self.__Q = np.zeros((size, size))
35
+ self.__M = np.zeros((size, 1))
36
+
37
+ if m is not None:
38
+ self.set_masses(m)
39
+ if q is not None:
40
+ self.set_charges(q)
41
+
42
+ def set_masses(self, m):
43
+ self.__M[:] = m
44
+
45
+ def set_charges(self, q):
46
+ q = np.asarray(q).reshape(self.__size, 1)
47
+ self.__Q[:] = q * q.T
48
+
49
+ def update_force(self, p_set):
50
+ self.__D[:] = dist.squareform(dist.pdist(p_set.X, "euclidean"))
51
+
52
+ with np.errstate(divide="ignore", invalid="ignore"):
53
+ self.__Fm[:] = self.__K * self.__Q / self.__D**3.0
54
+ np.fill_diagonal(self.__Fm, 0.0)
55
+
56
+ for i in range(self.__dim):
57
+ self.__V[:, :] = p_set.X[:, i]
58
+ self.__V[:, :] = (self.__V.T - p_set.X[:, i]).T
59
+ force_component = np.sum(self.__Fm * self.__V, axis=0)
60
+ self.__A[:, i] = force_component / self.__M[:, 0]
61
+
62
+ return self.__A
63
+
64
+ def getA(self):
65
+ return self.__A
66
+
67
+ A = property(getA)
68
+
69
+ def getF(self):
70
+ return self.__A * self.__M
71
+
72
+ F = property(getF)
@@ -0,0 +1,75 @@
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 sys
18
+
19
+ class Force(object):
20
+ """
21
+ The main abstract class used as interface for the forces classes
22
+
23
+ Constructor
24
+
25
+ :param size: the number of particles in the system
26
+ :param dim: the dimension of the system (3D, 2D..)
27
+ :param m: a vector containig the masses
28
+ :param Const: the force constants (Like G, K ...)
29
+ """
30
+
31
+ def __init__(self , size , dim , m=None , Conts=1.0 ):
32
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
33
+
34
+ def set_masses( self , m ):
35
+ """
36
+ Set the masses used for computing the forces.
37
+
38
+ :param m: An array containig the masses
39
+ """
40
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
41
+
42
+ def update_force( self , p_set ):
43
+ """
44
+ Computes the forces of the current status ad return the accelerations of the particles
45
+
46
+ :param p_set: Particles set obj.
47
+ """
48
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
49
+
50
+ def getA(self):
51
+ """
52
+ return the array of the acclerations
53
+ """
54
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
55
+
56
+ A = property( getA , doc="(property) return the array of the acclerations")
57
+
58
+ def getF(self):
59
+ """
60
+ returns the array of the forces
61
+ """
62
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
63
+
64
+ F = property( getF , doc="(property) returns the array of the forces" )
65
+
66
+
67
+ def get_const( self ):
68
+ """
69
+ returns the force contants
70
+ """
71
+ NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
72
+
73
+ const = property( get_const , doc="(property) returns the force contants")
74
+
75
+