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,226 @@
|
|
|
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
|
+
import scipy.spatial.distance as dist
|
|
11
|
+
|
|
12
|
+
import pyparticles.forces.force as fr
|
|
13
|
+
import pyparticles.pset.opencl_context as occ
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import pyopencl as cl
|
|
17
|
+
except ImportError:
|
|
18
|
+
cl = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PseudoBubble(fr.Force):
|
|
22
|
+
r"""Pseudo-bubble interaction used by the bubble demo."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, size, dim=3, m=None, Consts=(0.3, 2.0)):
|
|
25
|
+
self.__dim = int(dim)
|
|
26
|
+
self.__size = int(size)
|
|
27
|
+
self.__R = float(Consts[0])
|
|
28
|
+
self.__B = float(Consts[1])
|
|
29
|
+
|
|
30
|
+
self.__A = np.zeros((size, dim))
|
|
31
|
+
self.__M = np.zeros((size, 1))
|
|
32
|
+
self.__F = np.zeros((size, size))
|
|
33
|
+
self.__D = np.zeros((size, size))
|
|
34
|
+
self.__V = np.zeros((size, size))
|
|
35
|
+
|
|
36
|
+
if m is not None:
|
|
37
|
+
self.set_masses(m)
|
|
38
|
+
|
|
39
|
+
def set_masses(self, m):
|
|
40
|
+
self.__M[:] = m
|
|
41
|
+
|
|
42
|
+
def update_force(self, pset):
|
|
43
|
+
D = self.__D
|
|
44
|
+
D[:] = dist.squareform(dist.pdist(pset.X))
|
|
45
|
+
n, m = np.where(np.logical_and(D <= self.__R, D != 0.0))
|
|
46
|
+
|
|
47
|
+
self.__F[:] = 0.0
|
|
48
|
+
self.__F[n, m] = (-(self.__B / self.__R) * D[n, m] + self.__B) / D[n, m]
|
|
49
|
+
|
|
50
|
+
for i in range(pset.dim):
|
|
51
|
+
self.__V[:, :] = pset.X[:, i]
|
|
52
|
+
self.__V[:, :] = (self.__V.T - pset.X[:, i]).T
|
|
53
|
+
self.__A[:, i] = np.sum(
|
|
54
|
+
self.__F * self.__V / self.__M.T,
|
|
55
|
+
axis=0,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return self.__A
|
|
59
|
+
|
|
60
|
+
def getA(self):
|
|
61
|
+
return self.__A
|
|
62
|
+
|
|
63
|
+
A = property(getA)
|
|
64
|
+
|
|
65
|
+
def getF(self):
|
|
66
|
+
return self.__A * self.__M
|
|
67
|
+
|
|
68
|
+
F = property(getF)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PseudoBubbleOCL(fr.Force):
|
|
72
|
+
"""OpenCL implementation of the pseudo-bubble interaction."""
|
|
73
|
+
|
|
74
|
+
def __init__(self, size, dim=3, m=None, Consts=(0.3, 2.0), ocl_context=None):
|
|
75
|
+
if cl is None:
|
|
76
|
+
raise RuntimeError("PyOpenCL is required for PseudoBubbleOCL")
|
|
77
|
+
if int(dim) != 3:
|
|
78
|
+
raise ValueError("PseudoBubbleOCL currently supports only 3 dimensions")
|
|
79
|
+
|
|
80
|
+
self.__dim = int(dim)
|
|
81
|
+
self.__size = int(size)
|
|
82
|
+
|
|
83
|
+
if ocl_context is None:
|
|
84
|
+
self.__occ = occ.OpenCLcontext(
|
|
85
|
+
size,
|
|
86
|
+
dim,
|
|
87
|
+
occ.OCLC_X | occ.OCLC_A | occ.OCLC_M,
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
self.__occ = ocl_context
|
|
91
|
+
|
|
92
|
+
self.__dtype = self.__occ.dtype
|
|
93
|
+
self.__R = self.__dtype(Consts[0])
|
|
94
|
+
self.__B = self.__dtype(Consts[1])
|
|
95
|
+
self.__A = np.zeros((size, dim), dtype=self.__dtype)
|
|
96
|
+
self.__M = np.zeros((size, 1), dtype=self.__dtype)
|
|
97
|
+
|
|
98
|
+
self.__init_prog_cl()
|
|
99
|
+
if m is not None:
|
|
100
|
+
self.set_masses(m)
|
|
101
|
+
|
|
102
|
+
def __init_prog_cl(self):
|
|
103
|
+
source = r"""
|
|
104
|
+
__kernel void pseudo_bubble(
|
|
105
|
+
__global const float *X,
|
|
106
|
+
__global const float *M,
|
|
107
|
+
float R,
|
|
108
|
+
float B,
|
|
109
|
+
int accumulate,
|
|
110
|
+
__global float *A)
|
|
111
|
+
{
|
|
112
|
+
int i = get_global_id(0);
|
|
113
|
+
int sz = get_global_size(0);
|
|
114
|
+
|
|
115
|
+
int i0 = 3*i;
|
|
116
|
+
int i1 = i0 + 1;
|
|
117
|
+
int i2 = i0 + 2;
|
|
118
|
+
|
|
119
|
+
float4 at = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
|
120
|
+
float4 u = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
|
|
121
|
+
|
|
122
|
+
for (int n = 0; n < sz; ++n)
|
|
123
|
+
{
|
|
124
|
+
if (n == i) continue;
|
|
125
|
+
|
|
126
|
+
u.x = X[i0] - X[3*n];
|
|
127
|
+
u.y = X[i1] - X[3*n+1];
|
|
128
|
+
u.z = X[i2] - X[3*n+2];
|
|
129
|
+
|
|
130
|
+
float d = length(u);
|
|
131
|
+
if (d >= R || d == 0.0f) continue;
|
|
132
|
+
|
|
133
|
+
float f = (-B/R * d + B) / d;
|
|
134
|
+
at.x += u.x * f / M[i];
|
|
135
|
+
at.y += u.y * f / M[i];
|
|
136
|
+
at.z += u.z * f / M[i];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (accumulate)
|
|
140
|
+
{
|
|
141
|
+
A[i0] += at.x;
|
|
142
|
+
A[i1] += at.y;
|
|
143
|
+
A[i2] += at.z;
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
{
|
|
147
|
+
A[i0] = at.x;
|
|
148
|
+
A[i1] = at.y;
|
|
149
|
+
A[i2] = at.z;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
"""
|
|
153
|
+
self.__cl_program = cl.Program(self.__occ.CL_context, source).build()
|
|
154
|
+
self.__kernel = cl.Kernel(self.__cl_program, "pseudo_bubble")
|
|
155
|
+
|
|
156
|
+
def set_masses(self, m):
|
|
157
|
+
self.__M[:] = np.asarray(m, dtype=self.__dtype)
|
|
158
|
+
self.__occ.set_from_host("M", self.__M)
|
|
159
|
+
|
|
160
|
+
def update_force_device(self, pset, accumulate=False, host_authoritative=False):
|
|
161
|
+
if host_authoritative:
|
|
162
|
+
self.__occ.mark_host_modified("X")
|
|
163
|
+
self.__occ.sync_to_device("X", pset.X)
|
|
164
|
+
|
|
165
|
+
self.__kernel(
|
|
166
|
+
self.__occ.CL_queue,
|
|
167
|
+
(self.__size,),
|
|
168
|
+
None,
|
|
169
|
+
self.__occ.X_cla.data,
|
|
170
|
+
self.__occ.M_cla.data,
|
|
171
|
+
self.__R,
|
|
172
|
+
self.__B,
|
|
173
|
+
np.int32(bool(accumulate)),
|
|
174
|
+
self.__occ.A_cla.data,
|
|
175
|
+
)
|
|
176
|
+
self.__occ.mark_device_modified("A")
|
|
177
|
+
return self.__occ.A_cla
|
|
178
|
+
|
|
179
|
+
def update_force(self, pset):
|
|
180
|
+
self.update_force_device(pset, accumulate=False, host_authoritative=True)
|
|
181
|
+
self.__occ.sync_to_host("A", self.__A)
|
|
182
|
+
return self.__A
|
|
183
|
+
|
|
184
|
+
def getA(self):
|
|
185
|
+
return self.__A
|
|
186
|
+
|
|
187
|
+
A = property(getA)
|
|
188
|
+
|
|
189
|
+
def getF(self):
|
|
190
|
+
self.__occ.sync_to_host("A", self.__A)
|
|
191
|
+
return self.__A * self.__M
|
|
192
|
+
|
|
193
|
+
F = property(getF)
|
|
194
|
+
|
|
195
|
+
def get_ocl_context(self):
|
|
196
|
+
return self.__occ
|
|
197
|
+
|
|
198
|
+
ocl_context = property(get_ocl_context)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class PseudoBubbleFastOCL(PseudoBubbleOCL):
|
|
202
|
+
"""
|
|
203
|
+
Compatibility implementation for the historical experimental fast class.
|
|
204
|
+
|
|
205
|
+
The original 0.3.5 implementation was incomplete and contained invalid
|
|
206
|
+
OpenCL source. Until a spatially tiled implementation is introduced, use
|
|
207
|
+
the validated PseudoBubbleOCL kernel while preserving the public API.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
def __init__(
|
|
211
|
+
self,
|
|
212
|
+
size,
|
|
213
|
+
dim=3,
|
|
214
|
+
m=None,
|
|
215
|
+
Consts=(0.3, 2.0),
|
|
216
|
+
domain=(-5.5, 5.5),
|
|
217
|
+
ocl_context=None,
|
|
218
|
+
):
|
|
219
|
+
self.domain = domain
|
|
220
|
+
super(PseudoBubbleFastOCL, self).__init__(
|
|
221
|
+
size,
|
|
222
|
+
dim=dim,
|
|
223
|
+
m=m,
|
|
224
|
+
Consts=Consts,
|
|
225
|
+
ocl_context=ocl_context,
|
|
226
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
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 sys
|
|
19
|
+
import scipy.spatial.distance as dist
|
|
20
|
+
|
|
21
|
+
import pyparticles.forces.force as fr
|
|
22
|
+
|
|
23
|
+
class VanDerWaals( fr.Force ) :
|
|
24
|
+
def __init__(self , size , dim=3 , m=None , Consts=1.0 ):
|
|
25
|
+
|
|
26
|
+
self.__dim = dim
|
|
27
|
+
self.__size = size
|
|
28
|
+
|
|
29
|
+
self.__C = Consts # Hamaker coefficient (A)
|
|
30
|
+
|
|
31
|
+
self.__A = np.zeros( ( size , dim ) )
|
|
32
|
+
self.__F = np.zeros( ( size , dim ) )
|
|
33
|
+
self.__Fm = np.zeros( ( size , size ) )
|
|
34
|
+
|
|
35
|
+
self.__R = np.zeros( ( size , 1 ) )
|
|
36
|
+
if m != None :
|
|
37
|
+
self.set_messes( m )
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def set_masses( self , m ):
|
|
41
|
+
self.__R[:] = m
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def update_force( self , p_set ):
|
|
45
|
+
|
|
46
|
+
self.__D[:] = dist.squareform( dist.pdist( p_set.X , 'euclidean' ) )
|
|
47
|
+
|
|
48
|
+
return self.__A
|
|
49
|
+
|
|
50
|
+
def getA(self):
|
|
51
|
+
return self.__A
|
|
52
|
+
|
|
53
|
+
A = property( getA )
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def getF(self):
|
|
57
|
+
return self.__F
|
|
58
|
+
|
|
59
|
+
F = property( getF )
|
|
60
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
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 sys
|
|
19
|
+
import scipy.spatial.distance as dist
|
|
20
|
+
|
|
21
|
+
import pyparticles.forces.force as fr
|
|
22
|
+
|
|
23
|
+
class VectorFieldForce( fr.Force ) :
|
|
24
|
+
def __init__(self , size , dim=3 , m=None ):
|
|
25
|
+
self.__dim = dim
|
|
26
|
+
self.__size = size
|
|
27
|
+
self.__A = np.zeros( ( size , dim ) )
|
|
28
|
+
self.__M = np.zeros( ( size , size ) )
|
|
29
|
+
if m != None :
|
|
30
|
+
self.set_messes( m )
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def set_masses( self , m ):
|
|
34
|
+
self.__M[:] = m
|
|
35
|
+
|
|
36
|
+
def update_force( self , p_set ):
|
|
37
|
+
self.__A[:] = self.vect_fun( p_set.X )
|
|
38
|
+
return self.__A
|
|
39
|
+
|
|
40
|
+
def vect_fun( self , X ):
|
|
41
|
+
NotImplementedError(" %s : is virtual and must be overridden." % sys._getframe().f_code.co_name )
|
|
42
|
+
|
|
43
|
+
def getA(self):
|
|
44
|
+
return self.__A
|
|
45
|
+
|
|
46
|
+
A = property( getA )
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def getF(self):
|
|
50
|
+
return self.__A * self.__M[:]
|
|
51
|
+
|
|
52
|
+
F = property( getF )
|
|
@@ -0,0 +1,21 @@
|
|
|
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 os
|
|
19
|
+
import glob
|
|
20
|
+
|
|
21
|
+
__all__ = [ os.path.splitext( os.path.basename(f) )[0] for f in glob.glob(os.path.dirname(os.path.abspath(__file__))+"/*.py")]
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
|
|
20
|
+
def distance( x , y ):
|
|
21
|
+
"""
|
|
22
|
+
return the euclideian distance between *x* and *y*
|
|
23
|
+
"""
|
|
24
|
+
return np.sqrt( np.sum( (x-y)**2.0 ) )
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
from numpy import linalg as LA
|
|
19
|
+
|
|
20
|
+
import pyparticles.geometry.dist as dist
|
|
21
|
+
|
|
22
|
+
def box_intersects_sphere( b_min , b_max , c , r ):
|
|
23
|
+
"""
|
|
24
|
+
return True if the box defined by the opposite vertices *n_max*, *b max* intersect the sphere centred in *c* with a radius *r*
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
r2 = r**2.0
|
|
28
|
+
dmin = 0.0
|
|
29
|
+
|
|
30
|
+
if c[0] < b_min[0] :
|
|
31
|
+
dmin += ( c[0] - b_min[0] )**2.0
|
|
32
|
+
elif c[0] > b_max[0]:
|
|
33
|
+
dmin += ( c[0] - b_max[0] )**2.0
|
|
34
|
+
|
|
35
|
+
if c[1] < b_min[1] :
|
|
36
|
+
dmin += ( c[1] - b_min[1] )**2.0
|
|
37
|
+
elif c[1] > b_max[1]:
|
|
38
|
+
dmin += ( c[1] - b_max[1] )**2.0
|
|
39
|
+
|
|
40
|
+
if c[2] < b_min[2] :
|
|
41
|
+
dmin += ( c[2] - b_min[2] )**2.0
|
|
42
|
+
elif c[2] > b_max[2]:
|
|
43
|
+
dmin += ( c[2] - b_max[2] )**2.0
|
|
44
|
+
|
|
45
|
+
return dmin <= r2
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def sphere_intersect_sphere( c1 , r1 , c2 , r2 ):
|
|
49
|
+
"""
|
|
50
|
+
returns the average intersection point if the two spheres centred in *c1* and *c2* and radius *r1*, *r2* are intersecting, else it returns *None*
|
|
51
|
+
"""
|
|
52
|
+
d = dist.distance( c1 , c2 )
|
|
53
|
+
|
|
54
|
+
if r1 + r2 >= d :
|
|
55
|
+
|
|
56
|
+
u = ( c2 - c1 ) / LA.norm( c2 - c1 )
|
|
57
|
+
p = ( ( c1 + u*r1 ) + ( c2 - u*r2 ) ) / 2.0
|
|
58
|
+
|
|
59
|
+
return p
|
|
60
|
+
else :
|
|
61
|
+
return None
|
|
62
|
+
|