-
Notifications
You must be signed in to change notification settings - Fork 0
/
sphere.py
executable file
·122 lines (82 loc) · 3.23 KB
/
sphere.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python
import os
import sys
import numpy as np
import argparse as arg
def options():
'''Defines the options of the script.'''
parser = arg.ArgumentParser(description='''Calculates the position of a set of points onto
the surface of a sphere.''',
formatter_class=arg.ArgumentDefaultsHelpFormatter)
#
# Calculation Options
#
calc = parser.add_argument_group("Calculation Options")
calc.add_argument('-r', '--radius', default=1.0, type=float, dest='R',
help='''Radius of the Sphere.''')
calc.add_argument('-m', '--mode', default='rand', type=str,
choices=['rand', 'grid', 'fib'],
help='''Distribution of the points on the surface of the
Sphere.''', dest='Mode')
calc.add_argument('-n', default=50, type=int, dest='NPts',
help='''Number of points randomly distributed on the
Sphere.''')
calc.add_argument('--nphi', default=None, type=int, dest='NPhi',
help='Number of points of the grid along the z axis.')
calc.add_argument('--ntheta', default=None, type=int, dest='NTheta',
help='Number of points of the grid along the circle.')
#
# Output Options
#
out = parser.add_argument_group("Output Options")
out.add_argument('-o', '--output', default=None, type=str, dest='OutFile',
help='''Output File.''')
args = parser.parse_args()
Opts = vars(args)
return Opts
def sphere_grid(r, nphi, nth):
lp = nphi * 1j
lt = nth * 1j
phi, theta = np.mgrid[0:2*np.pi:lp, 0:np.pi:lt]
x = r * np.sin(theta) * np.cos(phi)
y = r * np.sin(theta) * np.sin(phi)
z = r * np.cos(theta)
coords = np.c_[x.ravel(), y.ravel(), z.ravel()]
coords = unique_rows(coords)
return coords
def sphere_rand(r, n):
coords = np.random.normal(size=(n,3))
coords = unique_rows(coords)
norm = np.linalg.norm(coords, axis=1)
coords = np.einsum('ij,i->ij', coords, 1 / norm)
return coords * r
def sphere_fib(r, n):
r = float(r)
angle = np.pi * (3. - np.sqrt(5.))
theta = np.arange(n) * angle
step = r / n
z = np.linspace(r - r / n , r / n - r, n)
rr = np.sqrt(r**2 - z**2)
coords = np.zeros((n,3))
coords[:,0] = rr * np.cos(theta)
coords[:,1] = rr * np.sin(theta)
coords[:,2] = z
return np.array(coords)
def unique_rows(data):
uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
return uniq.view(data.dtype).reshape(-1, data.shape[1])
if __name__ == '__main__':
Opts = options()
if Opts['Mode'] == 'rand':
coords = sphere_rand(Opts['R'], Opts['NPts'])
elif Opts['Mode'] == 'grid':
coords = sphere_grid(Opts['R'], Opts['NPhi'], Opts['NTheta'])
elif Opts['Mode'] == 'fib':
coords = sphere_fib(Opts['R'], Opts['NPts'])
N = len(coords)
coords = np.c_[np.ones(N), coords]
if not Opts['OutFile']:
Opts['OutFile'] = "sphere_%d" % N
with open("%s.xyz" % Opts['OutFile'], "w") as f:
f.write("%d\n\n"% N)
np.savetxt(f, coords, fmt="%5d %12.6f %12.6f %12.6f")