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
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from crystalbuilder.conversions.t3d import geo_to_tidy3d
|
|
3
|
+
from crystalbuilder import lattice as lat
|
|
4
|
+
from crystalbuilder import geometry as geo
|
|
5
|
+
from crystalbuilder.conversions import lumc as lc
|
|
6
|
+
import platform
|
|
7
|
+
if platform.system() == 'Windows':
|
|
8
|
+
pass
|
|
9
|
+
else:
|
|
10
|
+
import meep as mp
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
import lumpy.simobjects as so
|
|
14
|
+
except ModuleNotFoundError:
|
|
15
|
+
pass
|
|
16
|
+
debug = "off"
|
|
17
|
+
|
|
18
|
+
def vectorize(list):
|
|
19
|
+
"""Converts list of x,y,z coordinates to mp.Vector3 object
|
|
20
|
+
|
|
21
|
+
This simply assigns the first 3 indices to 'x','y','z' and returns the mp.Vector3('x','y','z').
|
|
22
|
+
Thus it will also work for any index-able data format (e.g. numpy arrays and existing mp.Vector3 objects)
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
list : ArrayLike
|
|
27
|
+
an ArrayLike object of length 3 (anything beyond will be ignored)
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
mp.Vector3()
|
|
32
|
+
mp.Vector3 object mp.Vector3(x,y,z)
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
x = list[0]
|
|
36
|
+
y = list[1]
|
|
37
|
+
z = list[2]
|
|
38
|
+
return mp.Vector3(x,y,z)
|
|
39
|
+
|
|
40
|
+
def unpack_supercell(supercell):
|
|
41
|
+
"""Turns supercell into a list of geometry objects
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
supercell : gm.SuperCell()
|
|
46
|
+
A SuperCell object from geometry.py
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
[structures]: list
|
|
51
|
+
list of the geometry objects in SuperCell
|
|
52
|
+
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
structures = supercell.structures
|
|
56
|
+
return structures
|
|
57
|
+
|
|
58
|
+
def flatten(list):
|
|
59
|
+
""" Some of these methods can accidentally create nested lists, so this function can be used in try statements to correct those """
|
|
60
|
+
try:
|
|
61
|
+
if isinstance(list, list):
|
|
62
|
+
flat_list = [item for sublist in list for item in sublist]
|
|
63
|
+
except:
|
|
64
|
+
flat_list = list
|
|
65
|
+
return flat_list
|
|
66
|
+
|
|
67
|
+
def _geo_to_meep(geometry_object, material, ismpb = False, **kwargs):
|
|
68
|
+
""" Lower-level function to convert Geometries into MEEP objects. It's recommended to call the geo_to_meep function instead.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
-----------
|
|
72
|
+
geometry_object : list or Geometry
|
|
73
|
+
an object or list of objects from geometry.py
|
|
74
|
+
|
|
75
|
+
material : mp.Material()
|
|
76
|
+
MEEP material for the converted object
|
|
77
|
+
|
|
78
|
+
ismpb : bool
|
|
79
|
+
MPB is a MEEP submodule that works for photonic crystals. The coordinate space is different than conventional MEEP. This arg determines if the resulting objects will use MPB coordinates or the MEEP ones (default)
|
|
80
|
+
|
|
81
|
+
**kwargs : string
|
|
82
|
+
lattice: mpb.lattice()
|
|
83
|
+
lattice for building MPB geometry, only necessary if mpb_mode is True. This is handled automatically by the higher level geo_to_mpb function
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
[geom_list] : list
|
|
89
|
+
list of MEEP objects
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
mpb_mode = ismpb
|
|
94
|
+
#print("MPB Mode is ", str(mpb_mode))
|
|
95
|
+
geom_list = []
|
|
96
|
+
if mpb_mode == True:
|
|
97
|
+
geo_lattice = kwargs.get("lattice", None)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
for m in geometry_object:
|
|
102
|
+
if isinstance(m, geo.SuperCell):
|
|
103
|
+
if debug=="on": print("This is running the iterable Supercell")
|
|
104
|
+
if ismpb == True:
|
|
105
|
+
innerlist = _geo_to_meep(m, material, ismpb=mpb_mode, lattice=geo_lattice)
|
|
106
|
+
geom_list.append(innerlist)
|
|
107
|
+
else:
|
|
108
|
+
innerlist = _geo_to_meep(m, material, ismpb=mpb_mode)
|
|
109
|
+
geom_list.append(innerlist)
|
|
110
|
+
|
|
111
|
+
elif isinstance(m, geo.Cylinder):
|
|
112
|
+
if debug=="on": print("This is running the iterable cylinder")
|
|
113
|
+
|
|
114
|
+
if ismpb == True:
|
|
115
|
+
k = vectorize(m.center)
|
|
116
|
+
newcent = mp.cartesian_to_lattice(k, geo_lattice)
|
|
117
|
+
else:
|
|
118
|
+
newcent = vectorize(m.center)
|
|
119
|
+
|
|
120
|
+
item = mp.Cylinder(radius=m.radius, axis= m.axis, height=m.height, center=newcent, material=material)
|
|
121
|
+
geom_list.append(item)
|
|
122
|
+
|
|
123
|
+
elif isinstance(m, geo.Triangle):
|
|
124
|
+
if debug=="on": print("This is running the iterable triangle")
|
|
125
|
+
|
|
126
|
+
newverts = []
|
|
127
|
+
for k in m.vertlist:
|
|
128
|
+
k = vectorize(k)
|
|
129
|
+
if mpb_mode == True:
|
|
130
|
+
newverts.append(mp.cartesian_to_lattice(k, geo_lattice))
|
|
131
|
+
elif mpb_mode == False:
|
|
132
|
+
newverts.append(k)
|
|
133
|
+
|
|
134
|
+
item = mp.Prism(vertices = newverts, axis = vectorize(m.axis), height = m.height, material=material)
|
|
135
|
+
geom_list.append(item)
|
|
136
|
+
|
|
137
|
+
elif isinstance(m, geo.Sphere):
|
|
138
|
+
if ismpb == True:
|
|
139
|
+
k = vectorize(m.center)
|
|
140
|
+
newcent = mp.cartesian_to_lattice(k, geo_lattice)
|
|
141
|
+
else:
|
|
142
|
+
newcent = vectorize(m.center)
|
|
143
|
+
|
|
144
|
+
item = mp.Sphere(radius=m.radius,center=newcent, material=material)
|
|
145
|
+
geom_list.append(item)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
except TypeError:
|
|
151
|
+
if isinstance(geometry_object, geo.SuperCell):
|
|
152
|
+
if debug=="on": print("This is running the single Supercell")
|
|
153
|
+
structs = unpack_supercell(geometry_object)
|
|
154
|
+
m = structs
|
|
155
|
+
newlist = _geo_to_meep(m, material)
|
|
156
|
+
geom_list.append(newlist)
|
|
157
|
+
|
|
158
|
+
elif isinstance(geometry_object, geo.Cylinder):
|
|
159
|
+
m = geometry_object
|
|
160
|
+
if debug=="on": print("This is running the single cylinder")
|
|
161
|
+
if ismpb == True:
|
|
162
|
+
k = vectorize(m.center)
|
|
163
|
+
newcent = mp.cartesian_to_lattice(k, geo_lattice)
|
|
164
|
+
else:
|
|
165
|
+
newcent = vectorize(m.center)
|
|
166
|
+
geom_list.append(mp.Cylinder(radius=m.radius, axis= m.axis, height=m.height, center=newcent, material=material))
|
|
167
|
+
|
|
168
|
+
elif isinstance(geometry_object, geo.Triangle):
|
|
169
|
+
if debug=="on": print("This is running the single triangle")
|
|
170
|
+
m = geometry_object
|
|
171
|
+
if ismpb == True:
|
|
172
|
+
newverts = []
|
|
173
|
+
for k in m.verttuple:
|
|
174
|
+
k = vectorize(k)
|
|
175
|
+
newverts.append(mp.cartesian_to_lattice(k, geo_lattice))
|
|
176
|
+
else:
|
|
177
|
+
newverts = vectorize(m.verttuple)
|
|
178
|
+
geom_list.append(mp.Prism(vertices = newverts, axis = vectorize(m.axis), height = m.height, material=material))
|
|
179
|
+
|
|
180
|
+
elif isinstance(geometry_object, geo.Sphere):
|
|
181
|
+
m = geometry_object
|
|
182
|
+
if ismpb == True:
|
|
183
|
+
k = vectorize(m.center)
|
|
184
|
+
newcent = mp.cartesian_to_lattice(k, geo_lattice)
|
|
185
|
+
else:
|
|
186
|
+
newcent = vectorize(m.center)
|
|
187
|
+
|
|
188
|
+
item = mp.Cylinder(radius=m.radius, center=newcent, material=material)
|
|
189
|
+
geom_list.append(item)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
return geom_list
|
|
194
|
+
|
|
195
|
+
def geo_to_meep(geometry_object, material):
|
|
196
|
+
"""Converts CrystalBuilder geometry object(s) to the corresponding MEEP object(s) with defined material.
|
|
197
|
+
|
|
198
|
+
This is a higher level wrapper of the _geo_to_meep function, which I have yet to document.
|
|
199
|
+
This simplifies the calling, as it only takes two arguments.
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
geometry_object : list or Geometry
|
|
204
|
+
an object or list of objects geometry.py
|
|
205
|
+
|
|
206
|
+
material : mp.Material()
|
|
207
|
+
MEEP material
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
-------
|
|
211
|
+
[meep_list]: list
|
|
212
|
+
list of MEEP objects
|
|
213
|
+
|
|
214
|
+
"""
|
|
215
|
+
geom_list = _geo_to_meep(geometry_object, material)
|
|
216
|
+
newlist = flatten(geom_list)
|
|
217
|
+
meep_list = flatten(newlist)
|
|
218
|
+
return meep_list
|
|
219
|
+
|
|
220
|
+
def geo_to_mpb(geometry_object, material, lattice):
|
|
221
|
+
"""Converts CrystalBuilder geometry object(s) to the corresponding MPB object(s) with defined material.
|
|
222
|
+
|
|
223
|
+
This is a higher level wrapper of the _geo_to_meep function, which I have yet to document.
|
|
224
|
+
MPB defines geometry on an arbitrary basis determined by the simulation's lattice. This requires an extra parameter, 'lattice'.
|
|
225
|
+
|
|
226
|
+
Parameters
|
|
227
|
+
----------
|
|
228
|
+
geometry_object : Geometry or list of Geometry
|
|
229
|
+
an object or list of objects
|
|
230
|
+
material : mp.Material()
|
|
231
|
+
MPB material
|
|
232
|
+
lattice : mpb.lattice()
|
|
233
|
+
lattice for MPB simulation, usually assigned to geometry_lattice
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
[mpb_list]: list
|
|
239
|
+
list of mpb objects
|
|
240
|
+
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
geom_list = _geo_to_meep(geometry_object, material, ismpb=True, lattice=lattice)
|
|
245
|
+
newlist = flatten(geom_list)
|
|
246
|
+
mpb_list = flatten(newlist)
|
|
247
|
+
return mpb_list
|
|
248
|
+
|
|
249
|
+
def _geo_to_lumerical(geometry_object, material):
|
|
250
|
+
"""
|
|
251
|
+
Converts Geometry object to list of lumerical objects
|
|
252
|
+
|
|
253
|
+
## IN PROGRESS ##
|
|
254
|
+
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
#get index from meep material, but treat it as a dielectric constant otherwise
|
|
258
|
+
try:
|
|
259
|
+
if isinstance(material, mp.Medium):
|
|
260
|
+
index = np.sqrt(material.epsilon_diag[0])
|
|
261
|
+
else:
|
|
262
|
+
index = material
|
|
263
|
+
except NameError:
|
|
264
|
+
index = material
|
|
265
|
+
|
|
266
|
+
geom_list = []
|
|
267
|
+
try:
|
|
268
|
+
for m in geometry_object:
|
|
269
|
+
if isinstance(m, geo.SuperCell):
|
|
270
|
+
if debug=="on": print("This is running the iterable Supercell")
|
|
271
|
+
innerlist = _geo_to_lumerical(m, material)
|
|
272
|
+
geom_list.append(innerlist)
|
|
273
|
+
|
|
274
|
+
elif isinstance(m, geo.Cylinder):
|
|
275
|
+
if debug=="on": print("This is running the iterable cylinder")
|
|
276
|
+
lmgeom = lc.convert_cylinder(m, material='dielectric', index=index)
|
|
277
|
+
geom_list.append(lmgeom)
|
|
278
|
+
|
|
279
|
+
elif isinstance(m, geo.Triangle):
|
|
280
|
+
if debug=="on": print("This is running the iterable Triangle")
|
|
281
|
+
lmgeom = lc.convert_prism(m, material='dielectric', index=index)
|
|
282
|
+
geom_list.append(lmgeom)
|
|
283
|
+
|
|
284
|
+
except TypeError:
|
|
285
|
+
if isinstance(geometry_object, geo.SuperCell):
|
|
286
|
+
if debug=="on": print("This is running the single Supercell")
|
|
287
|
+
structs = unpack_supercell(geometry_object)
|
|
288
|
+
m = structs
|
|
289
|
+
newlist = _geo_to_lumerical(m, material)
|
|
290
|
+
geom_list.append(newlist)
|
|
291
|
+
|
|
292
|
+
elif isinstance(geometry_object, geo.Cylinder):
|
|
293
|
+
m = geometry_object
|
|
294
|
+
if debug=="on": print("This is creating a single cylinder named")
|
|
295
|
+
lmgeom = lmgeom = lc.convert_cylinder(m, material='dielectric', index=index)
|
|
296
|
+
geom_list.append(lmgeom)
|
|
297
|
+
|
|
298
|
+
elif isinstance(geometry_object, geo.Triangle):
|
|
299
|
+
m = geometry_object
|
|
300
|
+
if debug=="on": print("This is running the single Triangle")
|
|
301
|
+
lmgeom = lc.convert_prism(m, material='dielectric', index=index)
|
|
302
|
+
geom_list.append(lmgeom)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
return geom_list
|
|
307
|
+
|
|
308
|
+
def to_geo_lattice(mpblattice):
|
|
309
|
+
"""converts mpb's `Lattice` to the CrystalBuilder Lattice
|
|
310
|
+
|
|
311
|
+
Parameters
|
|
312
|
+
----------
|
|
313
|
+
mpblattice : mp.Lattice()
|
|
314
|
+
mpb/MEEP lattice object
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
Returns
|
|
318
|
+
-------
|
|
319
|
+
lat.Lattice()
|
|
320
|
+
CrystalBuilder lattice object
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
if isinstance(mpblattice, mp.Lattice):
|
|
326
|
+
magnitude = np.asarray(mpblattice.size)
|
|
327
|
+
basis1 = np.asarray(mpblattice.basis1)
|
|
328
|
+
basis2 = np.asarray(mpblattice.basis2)
|
|
329
|
+
basis3 = np.asarray(mpblattice.basis3)
|
|
330
|
+
lattice = lat.Lattice(a1=basis1, a2=basis2, a3=basis3, magnitude=magnitude)
|
|
331
|
+
return lattice
|
|
332
|
+
else:
|
|
333
|
+
print("Error: Please pass a MEEP lattice object as the argument")
|
|
334
|
+
|
|
335
|
+
def to_mpb_lattice(geolattice):
|
|
336
|
+
"""converts crystalbuilder Lattice to the mpb lattice
|
|
337
|
+
|
|
338
|
+
Parameters
|
|
339
|
+
----------
|
|
340
|
+
lat.Lattice()
|
|
341
|
+
CrystalBuilder lattice object
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
Returns
|
|
345
|
+
-------
|
|
346
|
+
mpblattice : mp.Lattice()
|
|
347
|
+
mpb/MEEP lattice object
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
if isinstance(geolattice, lat.Lattice):
|
|
351
|
+
magnitude = np.asarray(geolattice.magnitude)
|
|
352
|
+
basis1 = np.asarray(geolattice.a1)
|
|
353
|
+
basis2 = np.asarray(geolattice.a2)
|
|
354
|
+
basis3 = np.asarray(geolattice.a3)
|
|
355
|
+
lattice = mp.Lattice(size = magnitude, basis1 = basis1, basis2 = basis2, basis3=basis3)
|
|
356
|
+
return lattice
|
|
357
|
+
else:
|
|
358
|
+
print("Error: Please pass a crystalbuilder lattice object as the argument")
|
|
359
|
+
|
|
360
|
+
if __name__ == '__main__':
|
|
361
|
+
"""testing code"""
|
|
362
|
+
|
|
363
|
+
# mat1 = mp.Medium(epsilon=4)
|
|
364
|
+
# geometry_lattice = mp.Lattice(size=mp.Vector3(1, 1),
|
|
365
|
+
# basis1=mp.Vector3(np.sqrt(3) / 2, 0.5),
|
|
366
|
+
# basis2=mp.Vector3(0,0.5))
|
|
367
|
+
|
|
368
|
+
# tri = geo.eqTriangle(1, .5)
|
|
369
|
+
# print(tri.vertices.shape)
|
|
370
|
+
# print(type(tri))
|
|
371
|
+
|
|
372
|
+
# newgeo = _geo_to_lumerical(tri, mat1)
|
|
373
|
+
|
|
374
|
+
# print(newgeo[0].out())
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
cylinder = geo.Cylinder.from_vertices([[0,0,0], [1,1,1]], radius=.2)
|
|
378
|
+
cylinder2 = geo.Cylinder(center=[1,1,0], radius=.1, height=3, axis=2)
|
|
379
|
+
newgeo = geo_to_tidy3d([cylinder, cylinder2], material=3)
|