ceviche 是一个开源的二维 fdfd 求解器,最近开发自动化设计工具,想要找一个物理场求解器测试自动化设计工具收敛性能,因此简单学习了下该开源求解器。

自动化设计工具旨在为使用各类仿真工具的用户提供从扫参到优化的飞跃,和扫参相差不大的设计流程,提供更强大的功能。

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
import numpy as np
import matplotlib as mpl
mpl.rcParams['figure.dpi']=100
import matplotlib.pylab as plt
import ceviche
from skimage.draw import disk
from ceviche.modes import insert_mode
from ceviche import fdfd_ez, jacobian
import autograd.numpy as npa
import collections
Slice = collections.namedtuple('Slice', 'x y')

def viz_sim(epsr, source1, source2, slices=[]):
simulation1 = fdfd_ez(omega1, dl, epsr, [Npml, Npml])
_, _, Ez1 = simulation1.solve(source1)
simulation2 = fdfd_ez(omega2, dl, epsr, [Npml, Npml])
_, _, Ez2 = simulation2.solve(source2)

fig, ax = plt.subplots(1, 3, constrained_layout=True, figsize=(9,3))
ceviche.viz.abs(Ez1, outline=epsr, ax=ax[0], cbar=False)
ceviche.viz.abs(Ez2, outline=epsr, ax=ax[1], cbar=False)
ceviche.viz.abs(epsr, ax=ax[2], cmap='Greys')
for sl in slices:
ax[0].plot(sl.x*np.ones(len(sl.y)), sl.y, 'w-', alpha=0.5)
ax[1].plot(sl.x*np.ones(len(sl.y)), sl.y, 'w-', alpha=0.5)

ax[0].set_title(r'$\lambda_1$ = %.2f $\mu$m' % (299792458/(omega1/2/np.pi)/1e-6))
ax[1].set_title(r'$\lambda_2$ = %.2f $\mu$m' % (299792458/(omega2/2/np.pi)/1e-6))

return (simulation1, simulation2, ax, fig)

def init_structure(Nx, Ny, Nwg, Nwd, Nox, Noy, Npml, edge_N, index_font, index_background):
epsr = np.ones((Nx, Ny)) * (index_font ** 2)
epsr[0:Nwg, (Ny-Nwd)//2:(Ny+Nwd)//2] = index_background ** 2
epsr[Nwg:Nwg+Nox, (edge_N) * Npml:(edge_N) * Npml+Noy] = index_background ** 2
epsr[Nwg+Nox:2*Nwg+Nox,(edge_N) * Npml: (edge_N) * Npml+Nwd] = index_background ** 2
epsr[Nwg+Nox:2*Nwg+Nox,(edge_N) * Npml+Noy-Nwd:(edge_N) * Npml+Noy] = index_background ** 2
input_slice = Slice(x=np.array(Npml+Nwg//2),
y=np.arange((Ny-Nwd)//2- Nwd, (Ny+Nwd)//2+Nwd))
output_slice1 = Slice(x=np.array(Nwg+Nox+Nwg//2),
y=np.arange(edge_N*Npml+Noy-2*Nwd, edge_N*Npml+Noy+Nwd))
output_slice2 = Slice(x=np.array(Nwg+Nox+Nwg//2),
y=np.arange( edge_N*Npml-Nwd, edge_N*Npml+2*Nwd))
return epsr, input_slice, output_slice1, output_slice2

def init_opt_structure(Nwg, circule_outer_radius, Npml, circule_inter_radius, epsr, index_font, index_background):
m = Nox // (circule_outer_radius * 2)
n = Noy // (circule_outer_radius * 2)
poles = []
for i in range(m):
for j in range(n):
rr, cc = disk((Nwg+2*circule_outer_radius*(j+0.5), (edge_N)*Npml+2*circule_outer_radius*(i+0.5)), circule_inter_radius)
poles.append([rr,cc])
epsr[rr,cc] = (index_font ** 2)
return epsr, poles

def set_opt_structure(poles, pole_index, epsr, index):
epsr[poles[pole_index][0],poles[pole_index][1]] = index ** 2
return epsr


if __name__ == "__main__":
# print("test")
# user_define
omega1=2*np.pi*200e12
omega2=2*np.pi*230e12
dl = 20e-9
opt_size_x = 2400e-9
opt_size_y = 2400e-9
wg_len = 2000e-9
wg_width = 500e-9
Npml = 20
edge_N = 4
index_background = 3.47
index_font = 1.22
circule_outer_radius = 6
circule_inter_radius = 5

Nx = int((opt_size_x + 2 * wg_len)*10e9 / (dl*10e9))
Ny = int((opt_size_y)*10e9 / (dl*10e9) + 2 * edge_N * Npml)
Nox = int((opt_size_x*10e9) / (dl*10e9))
Noy = int((opt_size_y*10e9) / (dl*10e9))
Nwg = int(wg_len*10e9 / (dl*10e9))
Nwd = int(wg_width*10e9 / (dl*10e9))

epsr, input_slice, output_slice1, output_slice2 = init_structure(Nx, Ny, Nwg, Nwd, Nox, Noy, Npml, edge_N, index_font, index_background)
epsr, poles = init_opt_structure(Nwg, circule_outer_radius, Npml, circule_inter_radius, epsr, index_font, index_background)

# ceviche.viz.abs(epsr, cbar=True)

source1 = insert_mode(omega1, dl, input_slice.x, input_slice.y, epsr, m=1)
source2 = insert_mode(omega2, dl, input_slice.x, input_slice.y, epsr, m=1)

probe1 = insert_mode(omega1, dl, output_slice1.x, output_slice1.y, epsr, m=1)
probe2 = insert_mode(omega2, dl, output_slice2.x, output_slice2.y, epsr, m=1)
epsr = set_opt_structure(poles, 0, epsr, index_background)
simulation1, simulation2, ax, fig = viz_sim(epsr, source1, source2, slices = [input_slice, output_slice1, output_slice2])

_, _, Ez1 = simulation1.solve(source1)
_, _, Ez2 = simulation2.solve(source2)

E01 = mode_overlap(Ez1, probe1)
E02 = mode_overlap(Ez2, probe2)

print(E01,E02)

plt.show()

以上是在 ceviche 创建的一个 1x2 端口器件,并在器件内部实现了类光子晶体结构。

实现结构为便于后续修改,所有结构的属性都参数化,后续仅需要通过需要参数就可以直达理想的结构。

⚓ Carl Zhao
🏢 逍遥科技有限公司
💭 曾经也是追光少年,然而少年归来已不再是少年,但依然在追光的路上。
📧 邮箱:1005513510@qq.com