crystalbuilder 0.5.4__py2.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.
Potentially problematic release.
This version of crystalbuilder might be problematic. Click here for more details.
- crystalbuilder/__init__.py +27 -0
- crystalbuilder/bilbao.py +297 -0
- crystalbuilder/conversions/lumc.py +36 -0
- crystalbuilder/conversions/t3d.py +179 -0
- crystalbuilder/convert.py +379 -0
- crystalbuilder/geometry.py +759 -0
- crystalbuilder/lattice.py +795 -0
- crystalbuilder/utils.py +22 -0
- crystalbuilder/vectors.py +279 -0
- crystalbuilder/viewer.py +82 -0
- crystalbuilder-0.5.4.dist-info/METADATA +12 -0
- crystalbuilder-0.5.4.dist-info/RECORD +14 -0
- crystalbuilder-0.5.4.dist-info/WHEEL +5 -0
- crystalbuilder-0.5.4.dist-info/licenses/LICENSE +674 -0
crystalbuilder/utils.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from crystalbuilder import convert
|
|
2
|
+
from crystalbuilder import lattice
|
|
3
|
+
from crystalbuilder import vectors
|
|
4
|
+
from crystalbuilder import bilbao
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
def MonkhorstPack(size):
|
|
8
|
+
"""
|
|
9
|
+
This is a direct copy of the Monkhorst-Pack k-space sampling method in ase (https://iopscience.iop.org/article/10.1088/1361-648X/aa680e)
|
|
10
|
+
|
|
11
|
+
This way there's no need to import ase.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
size : ndarray
|
|
16
|
+
number of points (kx, ky, kz) to sample reciprocal space. This should only be used in MPB, as it performs the necessary multiplication by the reciprocal lattice vectors
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
if np.less_equal(size, 0).any():
|
|
20
|
+
raise ValueError(f'Illegal size: {list(size)}')
|
|
21
|
+
kpts = np.indices(size).transpose((1, 2, 3, 0)).reshape((-1, 3))
|
|
22
|
+
return (kpts + 0.5) / size - 0.5
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from matplotlib import pyplot as plt
|
|
3
|
+
|
|
4
|
+
debug = 'off'
|
|
5
|
+
|
|
6
|
+
rounder = 50 #sets decimal rounding
|
|
7
|
+
#Needs Done
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def flatten(list):
|
|
11
|
+
flat_list = [item for sublist in list for item in sublist]
|
|
12
|
+
return flat_list
|
|
13
|
+
|
|
14
|
+
def angle_check(theta, unit):
|
|
15
|
+
if unit == 'degrees' or 'deg' or 'd' or 'degree':
|
|
16
|
+
radthet = np.radians(theta)
|
|
17
|
+
elif unit == 'radians' or 'rad' or 'r' or 'radian':
|
|
18
|
+
radthet = theta
|
|
19
|
+
else:
|
|
20
|
+
print("Error: Units must be 'degrees' or 'radians'")
|
|
21
|
+
return radthet
|
|
22
|
+
|
|
23
|
+
def shift(point, shift_vector):
|
|
24
|
+
"""
|
|
25
|
+
TO DO
|
|
26
|
+
|
|
27
|
+
shift point by the shift vector
|
|
28
|
+
"""
|
|
29
|
+
point_arr = np.asarray(point)
|
|
30
|
+
shiftvec = np.asarray(shift_vector)
|
|
31
|
+
shiftedpoint = point_arr.reshape(3,) + shiftvec.reshape(3,)
|
|
32
|
+
return shiftedpoint
|
|
33
|
+
|
|
34
|
+
def get_shift_vector(point, newpoint):
|
|
35
|
+
point_arr = np.asarray(point)
|
|
36
|
+
newpoint = np.asarray(newpoint)
|
|
37
|
+
shiftvec = newpoint.reshape(3,) - point_arr.reshape(3,)
|
|
38
|
+
return shiftvec
|
|
39
|
+
|
|
40
|
+
def shift_angle(point, theta, distance, unit='degrees'):
|
|
41
|
+
"""
|
|
42
|
+
Shifts in x-y plane a distance at angle theta
|
|
43
|
+
"""
|
|
44
|
+
point_arr = np.asarray(point)
|
|
45
|
+
shiftvec = rotate([[distance, 0, 0]], theta, axis=2, unit=unit)
|
|
46
|
+
print(shiftvec.T)
|
|
47
|
+
print(point_arr)
|
|
48
|
+
shiftedpoint = point_arr.reshape(3,) + shiftvec.reshape(3,)
|
|
49
|
+
return shiftedpoint
|
|
50
|
+
|
|
51
|
+
def rotate(point, theta, relative_point=(0,0,0), axis=2, unit='degrees', toarray=True):
|
|
52
|
+
"""
|
|
53
|
+
rotates counterclockwise a point or list of points about relative_point by theta in
|
|
54
|
+
This does a 2D rotation only, so string a few together to rotate in more than one axis
|
|
55
|
+
|
|
56
|
+
Parameters:
|
|
57
|
+
point (list of array_like)
|
|
58
|
+
theta (float)
|
|
59
|
+
relative_point (array_like)
|
|
60
|
+
axis (0,1,2)
|
|
61
|
+
unit (str): 'degrees' or 'radians'
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
List of coordinate lists (3-list)
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
radthet = angle_check(theta, unit)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
coordinatelist = []
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
for coord in point:
|
|
75
|
+
|
|
76
|
+
if axis==2:
|
|
77
|
+
newcoord = rotatez(coord, radthet, relative_point)
|
|
78
|
+
|
|
79
|
+
elif axis ==1:
|
|
80
|
+
newcoord = rotatey(coord, radthet, relative_point)
|
|
81
|
+
|
|
82
|
+
elif axis ==0:
|
|
83
|
+
newcoord = rotatex(coord, radthet, relative_point)
|
|
84
|
+
|
|
85
|
+
else:
|
|
86
|
+
print("Error: Check Axis Direction")
|
|
87
|
+
|
|
88
|
+
newcoord = newcoord.reshape(3,).tolist()
|
|
89
|
+
coordinatelist.append(newcoord)
|
|
90
|
+
if toarray==False:
|
|
91
|
+
new_coordinates=coordinatelist
|
|
92
|
+
else:
|
|
93
|
+
new_coordinates=np.asarray(coordinatelist)
|
|
94
|
+
|
|
95
|
+
if debug == 'on':
|
|
96
|
+
print('coordinates=\n', new_coordinates)
|
|
97
|
+
print('type= ', type(new_coordinates))
|
|
98
|
+
print('data type= ', type(new_coordinates[0][0]))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
return new_coordinates
|
|
102
|
+
|
|
103
|
+
def rotatex(point, theta, relative_point):
|
|
104
|
+
"""
|
|
105
|
+
rotates counterclockwise a point in x by theta radians about relative_point
|
|
106
|
+
"""
|
|
107
|
+
x = point[0]
|
|
108
|
+
y = point[1]
|
|
109
|
+
z = point[2]
|
|
110
|
+
|
|
111
|
+
relx = relative_point[0]
|
|
112
|
+
rely = relative_point[1]
|
|
113
|
+
relz = relative_point[2]
|
|
114
|
+
|
|
115
|
+
tmat = np.array([
|
|
116
|
+
[1,0,0,0],
|
|
117
|
+
[0, 1, 0, 0],
|
|
118
|
+
[0,0,1,0],
|
|
119
|
+
[relx, rely, relz,1]])
|
|
120
|
+
|
|
121
|
+
tnmat = np.array([
|
|
122
|
+
[1,0,0,0],
|
|
123
|
+
[0,1,0,0],
|
|
124
|
+
[0,0,1,0],
|
|
125
|
+
[-relx, -rely, -relz, 1]])
|
|
126
|
+
|
|
127
|
+
rxmat = np.array([
|
|
128
|
+
[1, 0, 0, 0],
|
|
129
|
+
[0, np.cos(theta), -np.sin(theta), 0],
|
|
130
|
+
[0, np.sin(theta), np.cos(theta), 0],
|
|
131
|
+
[0,0,0,1]
|
|
132
|
+
]).round(rounder)
|
|
133
|
+
if debug=='on':
|
|
134
|
+
print("rxmat", '= ', rxmat)
|
|
135
|
+
|
|
136
|
+
rt1mat = np.matmul(rxmat,tnmat)
|
|
137
|
+
if debug=='on':
|
|
138
|
+
print("rt1mat", '= ', rt1mat)
|
|
139
|
+
|
|
140
|
+
rt2mat = np.matmul(tmat,rt1mat)
|
|
141
|
+
if debug=='on':
|
|
142
|
+
print("rt2mat", '= ', rt2mat)
|
|
143
|
+
|
|
144
|
+
rotation = np.matmul(rt2mat, np.array([[x],[y],[z],[1]]))
|
|
145
|
+
return rotation[:3]
|
|
146
|
+
|
|
147
|
+
def rotatey(point, theta, relative_point):
|
|
148
|
+
"""
|
|
149
|
+
rotates counterclockwise a point in y by theta radians about relative_point
|
|
150
|
+
"""
|
|
151
|
+
x = point[0]
|
|
152
|
+
y = point[1]
|
|
153
|
+
z = point[2]
|
|
154
|
+
|
|
155
|
+
relx = relative_point[0]
|
|
156
|
+
rely = relative_point[1]
|
|
157
|
+
relz = relative_point[2]
|
|
158
|
+
|
|
159
|
+
tmat = np.array([
|
|
160
|
+
[1,0,0,0],
|
|
161
|
+
[0, 1, 0, 0],
|
|
162
|
+
[0,0,1,0],
|
|
163
|
+
[relx, rely, relz,1]])
|
|
164
|
+
|
|
165
|
+
tnmat = np.array([
|
|
166
|
+
[1,0,0,0],
|
|
167
|
+
[0,1,0,0],
|
|
168
|
+
[0,0,1,0],
|
|
169
|
+
[-relx, -rely, -relz, 1]])
|
|
170
|
+
|
|
171
|
+
rymat = np.array([
|
|
172
|
+
[np.cos(theta), 0, np.sin(theta), 0],
|
|
173
|
+
[0, 1, 0, 0],
|
|
174
|
+
[-np.sin(theta), 0, np.cos(theta), 0],
|
|
175
|
+
[0,0,0,1]
|
|
176
|
+
]).round(rounder)
|
|
177
|
+
if debug=='on':
|
|
178
|
+
print("rymat", '= ', rymat)
|
|
179
|
+
|
|
180
|
+
rt1mat = np.matmul(rymat,tnmat)
|
|
181
|
+
if debug=='on':
|
|
182
|
+
print("rt1mat", '= ', rt1mat)
|
|
183
|
+
|
|
184
|
+
rt2mat = np.matmul(tmat,rt1mat)
|
|
185
|
+
if debug=='on':
|
|
186
|
+
print("rt2mat", '= ', rt2mat)
|
|
187
|
+
|
|
188
|
+
rotation = np.matmul(rt2mat, np.array([[x],[y],[z],[1]]))
|
|
189
|
+
return rotation[:3]
|
|
190
|
+
|
|
191
|
+
def rotatez(point, theta, relative_point):
|
|
192
|
+
"""
|
|
193
|
+
rotates counterclockwise a point in z by theta radians about relative_point
|
|
194
|
+
"""
|
|
195
|
+
x = point[0]
|
|
196
|
+
y = point[1]
|
|
197
|
+
z = point[2]
|
|
198
|
+
|
|
199
|
+
relx = relative_point[0]
|
|
200
|
+
rely = relative_point[1]
|
|
201
|
+
relz = relative_point[2]
|
|
202
|
+
|
|
203
|
+
tmat = np.array([
|
|
204
|
+
[1,0,0,relx],
|
|
205
|
+
[0,1,0,rely],
|
|
206
|
+
[0,0,1,relz],
|
|
207
|
+
[0,0,0,1]])
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
tnmat = np.array([
|
|
211
|
+
[1,0,0,-relx],
|
|
212
|
+
[0,1,0,-rely],
|
|
213
|
+
[0,0,1,-relz],
|
|
214
|
+
[0,0,0,1]])
|
|
215
|
+
|
|
216
|
+
rzmat = np.array([
|
|
217
|
+
[np.cos(theta), -np.sin(theta),0 , 0],
|
|
218
|
+
[np.sin(theta), np.cos(theta), 0, 0],
|
|
219
|
+
[0, 0, 1, 0],
|
|
220
|
+
[0,0,0,1]
|
|
221
|
+
]).round(rounder)
|
|
222
|
+
if debug=='on':
|
|
223
|
+
print("translation matrix = \n", tmat)
|
|
224
|
+
print("negative translation matrix = \n", tnmat)
|
|
225
|
+
print("rzmat", '=\n', rzmat)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
rt1mat = np.matmul(rzmat,tnmat)
|
|
229
|
+
if debug=='on':
|
|
230
|
+
print("rt1mat", '=\n', rt1mat)
|
|
231
|
+
|
|
232
|
+
rt2mat = np.matmul(tmat,rt1mat)
|
|
233
|
+
if debug=='on':
|
|
234
|
+
print("rt2mat", '=\n', rt2mat)
|
|
235
|
+
|
|
236
|
+
rotation = np.matmul(rt2mat, np.array([[x],[y],[z],[1]]))
|
|
237
|
+
return rotation[:3]
|
|
238
|
+
|
|
239
|
+
def basis_change(basis1, basis2, point_in_basis1):
|
|
240
|
+
"""
|
|
241
|
+
makes column vectors from basis1 and basis2, then determines the change-of-basis matrix. Applies this to specified point and returns the coordinate in the other basis.
|
|
242
|
+
|
|
243
|
+
Both bases need to be defined in cartesian basis, but the output will be in terms of basis2
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
Parameters
|
|
247
|
+
----------
|
|
248
|
+
basis1: basis in 3x3 list or array, or 'cartesian'
|
|
249
|
+
basis2: basis in 3x3 list or array, or 'cartesian'
|
|
250
|
+
point_in_basis1: 3-list point specified in units of basis 1
|
|
251
|
+
|
|
252
|
+
"""
|
|
253
|
+
cartbasis = [[1,0,0], [0,1,0], [0,0,1]]
|
|
254
|
+
try:
|
|
255
|
+
if basis1 == 'cartesian': basis1=cartbasis
|
|
256
|
+
except ValueError:
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
if basis2 == 'cartesian': basis2=cartbasis
|
|
261
|
+
except ValueError:
|
|
262
|
+
pass
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
bas1_arr = np.transpose(np.asarray(basis1))
|
|
266
|
+
bas2_arr = np.transpose(np.asarray(basis2))
|
|
267
|
+
point_arr = np.asarray(point_in_basis1).reshape(3,1)
|
|
268
|
+
|
|
269
|
+
newpoint = np.matmul(bas1_arr, point_arr)
|
|
270
|
+
outpoint = np.matmul(bas2_arr, newpoint)
|
|
271
|
+
return outpoint.reshape(3,)
|
|
272
|
+
|
|
273
|
+
def cart_to_pol(point):
|
|
274
|
+
x = point[0]
|
|
275
|
+
y = point[1]
|
|
276
|
+
z = point[2]
|
|
277
|
+
r = np.sqrt((x**2 + y**2))
|
|
278
|
+
theta = np.arctan2(y, x)+np.pi
|
|
279
|
+
return [r, theta, z]
|
crystalbuilder/viewer.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import vedo
|
|
2
|
+
import crystalbuilder
|
|
3
|
+
import crystalbuilder.geometry as geo
|
|
4
|
+
|
|
5
|
+
vedo.settings.default_backend='vtk'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def add_to_visualizer(structures, plot, **kwargs):
|
|
10
|
+
for object in structures:
|
|
11
|
+
if isinstance(object, geo.Cylinder):
|
|
12
|
+
plot += visualize_cylinder(object, **kwargs)
|
|
13
|
+
elif isinstance(object, geo.Sphere):
|
|
14
|
+
plot += visualize_sphere(object, **kwargs)
|
|
15
|
+
elif isinstance(object, geo.SuperCell):
|
|
16
|
+
plot += visualize_supercell(object, **kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def visualize(structures, plotter_style=9, **kwargs):
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
-----------
|
|
24
|
+
structures : list of geo
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
plot = vedo.Plotter(axes=plotter_style)
|
|
29
|
+
|
|
30
|
+
add_to_visualizer(structures, plot)
|
|
31
|
+
|
|
32
|
+
# for object in structures:
|
|
33
|
+
# if isinstance(object, geo.Structure):
|
|
34
|
+
# if isinstance(object, geo.Cylinder):
|
|
35
|
+
# obj = visualize_cylinder(object, **kwargs)
|
|
36
|
+
# plot += obj
|
|
37
|
+
# elif isinstance(object, geo.SuperCell):
|
|
38
|
+
# obj = visualize_supercell(object, **kwargs)
|
|
39
|
+
# plot += obj
|
|
40
|
+
# elif isinstance(object, geo.Sphere):
|
|
41
|
+
# obj = visualize_sphere(object, **kwargs)
|
|
42
|
+
# plot += obj
|
|
43
|
+
# elif isinstance(object, list):
|
|
44
|
+
# for n in object:
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
return plot
|
|
48
|
+
|
|
49
|
+
def visualize_cylinder(cylinder, **kwargs):
|
|
50
|
+
center = cylinder.center
|
|
51
|
+
radius = cylinder.radius
|
|
52
|
+
height = cylinder.height
|
|
53
|
+
axis = cylinder.axis
|
|
54
|
+
name = str(cylinder.center)
|
|
55
|
+
obj = vedo.Cylinder(pos=center, r=radius, height=height, axis=axis, **kwargs).legend(name)
|
|
56
|
+
obj.name = name
|
|
57
|
+
return obj
|
|
58
|
+
|
|
59
|
+
def visualize_sphere(sphere, **kwargs):
|
|
60
|
+
center = sphere.center
|
|
61
|
+
radius = sphere.radius
|
|
62
|
+
name = str(sphere.center)
|
|
63
|
+
obj = vedo.Sphere(pos=center, r=radius, **kwargs).legend(name)
|
|
64
|
+
obj.name = name
|
|
65
|
+
return obj
|
|
66
|
+
|
|
67
|
+
def visualize_supercell(SuperCell, **kwargs):
|
|
68
|
+
objects = []
|
|
69
|
+
for structure in SuperCell:
|
|
70
|
+
if isinstance(structure, geo.Cylinder):
|
|
71
|
+
objects.append(visualize_cylinder(structure, **kwargs))
|
|
72
|
+
elif isinstance(structure, geo.Sphere):
|
|
73
|
+
objects.append(visualize_sphere(structure, **kwargs))
|
|
74
|
+
return objects
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
cylinder1 = geo.Cylinder(center=(0,0,0), radius=1, height=3, axis=2)
|
|
81
|
+
cylinder2 = geo.Cylinder(center=(5,5,0), radius=2, height=6, axis=1)
|
|
82
|
+
visualize([cylinder1, cylinder2])
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crystalbuilder
|
|
3
|
+
Version: 0.5.4
|
|
4
|
+
Summary: A package for building 3D photonic crystals
|
|
5
|
+
Author: Brandon Hacha
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: beautifulsoup4
|
|
8
|
+
Requires-Dist: matplotlib
|
|
9
|
+
Requires-Dist: numpy
|
|
10
|
+
Requires-Dist: vedo
|
|
11
|
+
Provides-Extra: full
|
|
12
|
+
Requires-Dist: tidy3d; extra == 'full'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
crystalbuilder/__init__.py,sha256=_Jc_rgu9WcSSuOs_uZw2NIFojARRBSU_EA59DY9vCzw,1368
|
|
2
|
+
crystalbuilder/bilbao.py,sha256=660d06o8I3NAqTSLHrOK7kTf-Lnr1rKhp2smw_giafA,10994
|
|
3
|
+
crystalbuilder/convert.py,sha256=2f8EcLg0SAyObjcdhL6m-j1N8qBLy_XIo-3MugLGYnM,12691
|
|
4
|
+
crystalbuilder/geometry.py,sha256=CPioM1OTVQUutJoX_XpVa3kYOXhJ9B3N4Vbmfjs5M1c,24647
|
|
5
|
+
crystalbuilder/lattice.py,sha256=1y8U9iJKbYIqTeX4qVR2k8E2lAjsbyx1zUz4ATswU7A,33555
|
|
6
|
+
crystalbuilder/utils.py,sha256=INkhGf8Jat_YH1K3TghL6mw5cS__CVILQgdo7u9g_SY,818
|
|
7
|
+
crystalbuilder/vectors.py,sha256=uf5StYewaQsY9R1hrtZtzg-5MkeN0DR7VPen2Tux_TU,7686
|
|
8
|
+
crystalbuilder/viewer.py,sha256=r37owd9kPre32D2zvIQUqImgySbR0CiuMFfdRfuDYVY,2474
|
|
9
|
+
crystalbuilder/conversions/lumc.py,sha256=WFJbt8Dgy5myWlIzdciHNMpmpeEV3TvmqB6SSvFZ3nw,1327
|
|
10
|
+
crystalbuilder/conversions/t3d.py,sha256=9QzRImME7muk7kG43Nnu7XUpjJi9um0zwWllKbBQM-s,6627
|
|
11
|
+
crystalbuilder-0.5.4.dist-info/METADATA,sha256=e1N8-PHxYERJpcdlnFEoNDFJdRmRyBm_96gdC2bNl40,312
|
|
12
|
+
crystalbuilder-0.5.4.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
13
|
+
crystalbuilder-0.5.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
+
crystalbuilder-0.5.4.dist-info/RECORD,,
|