├── .gitignore ├── README.md ├── SUMMARY.md ├── docs ├── .nojekyll ├── 3db功分.md ├── README.md ├── _coverpage.md ├── _images │ ├── 2021-01-04-17-29-03.png │ ├── 2021-01-06-15-58-39.png │ ├── 2021-01-06-15-59-44.png │ └── 2021-01-06-16-01-34.png ├── _media │ └── icon.svg ├── _sidebar.md ├── index.html ├── 例程.md ├── 前言.md ├── 安装.md ├── 测试.md └── 附录.md └── src ├── gen_data └── main.py ├── material.mdf └── transpose ├── gen_data.py └── initbase.py /.gitignore: -------------------------------------------------------------------------------- 1 | /testdocs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 文档地址 2 | 3 | https://photonic-ai-communication.github.io/lumerical-python-script/#/ 4 | 5 | 6 | ## 说明 7 | 8 | 此文档为记录、备份lumerical fdtd/mode 的python api以及相关使用方法。 9 | 10 | 以供组内成员查阅、使用。 11 | 12 | 文档中所涉及到的所有源码均在src文件夹目录下 13 | 14 | material.mdf为材料文件 -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # SUMMARY 2 | 3 | ### 前言 4 | 5 | * [前言](前言.md) 6 | 7 | ### 安装 8 | * [安装:前言](安装.md#init) 9 | * [lumerical](安装.md#lumerical) 10 | * [python](安装.md#python) 11 | * [python+lumerical](安装.md#python+lumerical) 12 | * [结语](安装.md#结尾) 13 | 14 | ### 例程 15 | * [例程:简单的例子](例程.md#ladder) 16 | * [发生了什么?](例程.md#what_happend) 17 | 18 | ### 附录 19 | 20 | * [关于python中的包管理](附录.md#pipinstall) 21 | * [更换下载源](附录.md#change_source) 22 | * [包安装方式](附录.md#install) 23 | * [关于函数、方法的查询](附录.md#how2find) -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/docs/.nojekyll -------------------------------------------------------------------------------- /docs/3db功分.md: -------------------------------------------------------------------------------- 1 | # 例程:功率分支器 2 | 3 | 在这个例子中,我们的设计目标是一个简单的片上功率分支器,光从一端输入,从另一端的两个端口输出。 4 | 5 | 要求损耗尽可能低,即3db功分器 6 | 7 | > 本节例程源码处于src/transpose目录下 8 | 9 | 这个例程主要含有以下功能: 10 | 11 | 1. 最简单的拓扑优化(爬山、dbs……管你怎么叫了……) 12 | 2. 多进程同时仿真 13 | 3. 模式分解器的使用 14 | 15 | ## 开始 16 | 17 | 未完待续…… -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 文档地址 2 | 3 | https://photonic-ai-communication.github.io/lumerical-python-script/#/ 4 | 5 | 6 | ## 说明 7 | 8 | 此文档为记录、备份lumerical fdtd/mode 的python api以及相关使用方法。 9 | 10 | 以供组内成员查阅、使用。 11 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![logo](_media/icon.svg) 4 | 5 | # lumerical+python=efficiency 3.5 6 | 7 | > 用python操作lumerical的api进行各种仿真 8 | 9 | 10 | [GitHub](https://github.com/Photonic-AI-Communication/lumerical-python-script/) 11 | [Get Started](#前言) -------------------------------------------------------------------------------- /docs/_images/2021-01-04-17-29-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/docs/_images/2021-01-04-17-29-03.png -------------------------------------------------------------------------------- /docs/_images/2021-01-06-15-58-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/docs/_images/2021-01-06-15-58-39.png -------------------------------------------------------------------------------- /docs/_images/2021-01-06-15-59-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/docs/_images/2021-01-06-15-59-44.png -------------------------------------------------------------------------------- /docs/_images/2021-01-06-16-01-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/docs/_images/2021-01-06-16-01-34.png -------------------------------------------------------------------------------- /docs/_media/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | I thought what I'd do was, I'd pretend I was one of those deaf-mutes 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | 2 | * 快速开始 3 | * [前言](前言.md) 4 | * [安装](安装.md) 5 | 6 | * 例程 7 | * [简单的例子](例程.md) 8 | * [功率分支器](3db功分.md) 9 | 10 | 11 | * 附录 12 | * [附录](附录.md) 13 | * [特殊代码测试](测试.md) -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/例程.md: -------------------------------------------------------------------------------- 1 | # 例程:简单的例子 2 | 3 | 我们先来看一个简单的仿真例子,这个例子中我们定义了一个简单的器件,并放置了光源,定义了仿真区域、边界条件、输入模式等等,并在最后将仿真的结果通过监视器输出,以numpy格式导入到了python中,并最后通过matplotlib可视化。 4 | 5 | **注意:本示例中引用了bidict、matplotlib等软件包,若没有安装,请参考附录中的[软件包安装](附录.md#pipinstall)** 6 | 7 | ``` 8 | import lumapi 9 | import numpy as np 10 | from collections import OrderedDict 11 | from bidict import bidict 12 | import matplotlib.pyplot as plt 13 | 14 | def init_base(mode,size=(2,2)): 15 | mode.switchtolayout() 16 | # 基底生成 17 | # mode.importmaterialdb("fdtd_files/material.mdf") #加载材料数据 18 | mode.addrect(x=0, y=0.0, z=-1.11e-6,x_span=2e-5,y_span=1e-5,z_span=2e-6,name="box",material="SiO2 (Glass) - Palik") 19 | mode.addrect(x=0, y=0.0, z=0,x_span=2.6e-6,y_span=2.6e-6,z_span=0.22e-6,name="Si (Silicon) - Palik",material="Si (Silicon) - Palik") 20 | mode.addrect(x=-5.15e-6, y=0.0, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="in", 21 | material="Si (Silicon) - Palik") 22 | mode.addrect(x=5.15e-6, y=0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out1", 23 | material="Si (Silicon) - Palik") 24 | mode.addrect(x=5.15e-6, y=-0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out2", 25 | material="Si (Silicon) - Palik") 26 | mode.addmesh(x=0, y=0, z=0, x_span=2.6e-6, y_span=2.6e-6, z_span=0.22e-6, name="mesh", 27 | dx=0.02e-6,dy=0.02e-6,dz=0.02e-6,) 28 | mode.addvarfdtd(x=0, y=0, z=0,x_span=4e-6, y_span=4e-6, z_span=0.8e-6,simulation_time=1000e-15,x0=-1.48565e-6) 29 | 30 | #通过OrderedDict顺序设置模型参数 31 | source_props = OrderedDict([("name", "source"), ("injection axis", "x"), 32 | ("x", -1.7e-6), ("y", 0),("y span", 2e-6), 33 | ("selected mode number",2), 34 | ("center wavelength",1.55e-6),("wavelength span",0.2e-6), 35 | ("optimize for short pulse", 1) 36 | ]) 37 | mode.addmodesource(properties=source_props) 38 | 39 | # OrderedDict也可以这样给 40 | mode.addpower(properties=OrderedDict([("name", "T1"), ("monitor type", "2D X-normal"), 41 | ("x", 1.45e-6), ("y", 0.75e-6),("z",0), 42 | ("y span", 0.5e-6),("z span",0.4e-6), 43 | ("override global monitor settings", True),("frequency points",1)])) 44 | mode.addpower(properties=OrderedDict([("name", "T2"), ("monitor type", "2D X-normal"), 45 | ("x", 1.45e-6), ("y", -0.75e-6),("z",0), 46 | ("y span", 0.5e-6),("z span",0.4e-6), 47 | ("override global monitor settings", True),("frequency points",1)])) 48 | 49 | 50 | # pattern生成 51 | rows, columns = size[0], size[1] 52 | mode.addstructuregroup(name="666") 53 | x_span = 2.6e-6 / columns 54 | y_span = 2.6e-6 / rows 55 | for row in range(rows): 56 | for column in range(columns): 57 | #模型在放置之后,默认选择的就是这个模型,就像下面这里,放置矩形之后可以直接将其加入到模型组之中,不用重新选择 58 | mode.addrect(x=-1.3e-6 + x_span / 2 + column * x_span, x_span=x_span, 59 | y=1.3e-6 - y_span / 2 - row * y_span, y_span=y_span, 60 | z=0, z_span=0.22e-6, name=str(row) + "r" + str(column) + "c", 61 | material="etch") 62 | mode.addtogroup("666") 63 | 64 | def change_pattern(mode,pattern_matrix): 65 | mode.switchtolayout() 66 | pattern_dic=bidict({ 67 | "Si (Silicon) - Palik":1, 68 | "etch":0 69 | }) 70 | for row in range(pattern_matrix.shape[0]): 71 | for column in range(pattern_matrix.shape[1]): 72 | mode.select("666::"+str(row)+"r"+str(column)+"c") 73 | pix = mode.getObjectBySelection() 74 | material_name=pix.material 75 | if pattern_dic[material_name]!=pattern_matrix[row][column]: 76 | pix.material=pattern_dic.inverse[pattern_matrix[row][column]] 77 | 78 | def get_result(mode): 79 | t1 = mode.getresult("T1", "E")["E"].squeeze() 80 | t2 = mode.getresult("T2", "E")["E"].squeeze() 81 | #这里a,b是两个监视器的电场幅值,即xyz方向的平方相加开根 82 | a = np.sqrt(np.sum(np.power(np.abs(t1), 2), axis=1)) 83 | b = np.sqrt(np.sum(np.power(np.abs(t2), 2), axis=1)) 84 | return a,b 85 | 86 | if __name__ == '__main__': 87 | row_num = 5 88 | column_num = 5 89 | 90 | mode = lumapi.MODE() 91 | init_base(mode, size=(row_num, column_num)) 92 | #保存为项目文件 93 | mode.save("fdtd_files/base"+str(row_num)+"_"+str(column_num)+".lms") 94 | 95 | # 初始化pattern 96 | best_pattern_matrix = np.random.randint(0, 2, (row_num, column_num)) 97 | change_pattern(mode,best_pattern_matrix) 98 | mode.run() 99 | a,b=get_result(mode) 100 | 101 | #绘图,可以和软件中自带的可视化比较一下 102 | fig, ax = plt.subplots(1) 103 | ax.plot(np.arange(len(a)),a,c='r',label='T1') 104 | ax.plot(np.arange(len(b)), b, c='b', label='T2') 105 | plt.legend() 106 | plt.show() 107 | 108 | ``` 109 | 110 | 以上程序运行结束之后会画出两个输出端口的电场幅值分布: 111 | 112 | ![](_images/2021-01-06-15-58-39.png) 113 | 114 | 115 | 对应mode中的监视器可视化: 116 | 117 | ![](_images/2021-01-06-15-59-44.png) 118 | 119 | 器件结构: 120 | 121 | ![](_images/2021-01-06-16-01-34.png) 122 | 123 | 能够看到数据正确。 124 | 125 | ********* 126 | ## 发生了什么? 127 | 如果程序运行顺利,我们应该能看到一个非常酷炫的效果,别慌。 128 | 129 | 接下来我们详细分析程序运行逻辑 130 | 131 | ``` 132 | if __name__ == '__main__': #这里是程序的入口,运行的时候这里最先运行 133 | row_num = 5 #定义了我们器件的离散网格数量 134 | column_num = 5 135 | 136 | mode = lumapi.MODE() #通过lumapi,我们启动了一个mode仿真窗口,mode就代表了这个仿真的窗口对象,接下来的一系列操作都得通过mode这个对象进行 137 | 138 | init_base(mode, size=(row_num, column_num)) #我们将mode对象和我们定义的器件离散网格数量传入到了init_base这个函数当中,这个函数就开始生成我们器件的基本结构。 139 | 140 | 141 | #保存为项目文件 142 | mode.save("fdtd_files/base"+str(row_num)+"_"+str(column_num)+".lms") 143 | 144 | # 初始化pattern 145 | best_pattern_matrix = np.random.randint(0, 2, (row_num, column_num)) #通过numpy,我们生成了一个随机的二值化矩阵,矩阵大小同样为离散网格的数量 146 | 147 | change_pattern(mode,best_pattern_matrix) # change_pattern函数接收mode对象和我们随机的矩阵,将器件结构更改为随机矩阵对应的结构 148 | 149 | mode.run() #开始仿真 150 | a,b=get_result(mode) #仿真结束,get_result函数从mode对象中获取我们所需要的结果。 151 | 152 | #绘图,可以和软件中自带的可视化比较一下 153 | fig, ax = plt.subplots(1) 154 | ax.plot(np.arange(len(a)),a,c='r',label='T1') 155 | ax.plot(np.arange(len(b)), b, c='b', label='T2') 156 | plt.legend() 157 | plt.show() 158 | 159 | ``` 160 | 161 | 经过main函数之后,我们打开了一个mode仿真窗口,初始化了器件结构,更改了结构,并进行了仿真,最后得到了仿真结果,并通过matplotlib可视化。 162 | 163 | 接下来对程序中进行各种处理的函数进行分析: 164 | 165 | ``` 166 | def init_base(mode,size=(2,2)): 167 | mode.switchtolayout() 168 | # 基底生成 169 | # mode.importmaterialdb("fdtd_files/material.mdf") #加载材料数据 170 | mode.addrect(x=0, y=0.0, z=-1.11e-6,x_span=2e-5,y_span=1e-5,z_span=2e-6,name="box",material="SiO2 (Glass) - Palik") 171 | mode.addrect(x=0, y=0.0, z=0,x_span=2.6e-6,y_span=2.6e-6,z_span=0.22e-6,name="Si (Silicon) - Palik",material="Si (Silicon) - Palik") 172 | mode.addrect(x=-5.15e-6, y=0.0, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="in", 173 | material="Si (Silicon) - Palik") 174 | mode.addrect(x=5.15e-6, y=0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out1", 175 | material="Si (Silicon) - Palik") 176 | mode.addrect(x=5.15e-6, y=-0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out2", 177 | material="Si (Silicon) - Palik") 178 | mode.addmesh(x=0, y=0, z=0, x_span=2.6e-6, y_span=2.6e-6, z_span=0.22e-6, name="mesh", 179 | dx=0.02e-6,dy=0.02e-6,dz=0.02e-6,) 180 | mode.addvarfdtd(x=0, y=0, z=0,x_span=4e-6, y_span=4e-6, z_span=0.8e-6,simulation_time=1000e-15,x0=-1.48565e-6) 181 | 182 | #通过OrderedDict顺序设置模型参数 183 | source_props = OrderedDict([("name", "source"), ("injection axis", "x"), 184 | ("x", -1.7e-6), ("y", 0),("y span", 2e-6), 185 | ("selected mode number",2), 186 | ("center wavelength",1.55e-6),("wavelength span",0.2e-6), 187 | ("optimize for short pulse", 1) 188 | ]) 189 | mode.addmodesource(properties=source_props) 190 | 191 | # OrderedDict也可以这样给 192 | mode.addpower(properties=OrderedDict([("name", "T1"), ("monitor type", "2D X-normal"), 193 | ("x", 1.45e-6), ("y", 0.75e-6),("z",0), 194 | ("y span", 0.5e-6),("z span",0.4e-6), 195 | ("override global monitor settings", True),("frequency points",1)])) 196 | mode.addpower(properties=OrderedDict([("name", "T2"), ("monitor type", "2D X-normal"), 197 | ("x", 1.45e-6), ("y", -0.75e-6),("z",0), 198 | ("y span", 0.5e-6),("z span",0.4e-6), 199 | ("override global monitor settings", True),("frequency points",1)])) 200 | 201 | 202 | # pattern生成 203 | rows, columns = size[0], size[1] 204 | mode.addstructuregroup(name="666") 205 | x_span = 2.6e-6 / columns 206 | y_span = 2.6e-6 / rows 207 | for row in range(rows): 208 | for column in range(columns): 209 | #模型在放置之后,默认选择的就是这个模型,就像下面这里,放置矩形之后可以直接将其加入到模型组之中,不用重新选择 210 | mode.addrect(x=-1.3e-6 + x_span / 2 + column * x_span, x_span=x_span, 211 | y=1.3e-6 - y_span / 2 - row * y_span, y_span=y_span, 212 | z=0, z_span=0.22e-6, name=str(row) + "r" + str(column) + "c", 213 | material="etch") 214 | mode.addtogroup("666") 215 | 216 | ``` 217 | 程序中的注释写的应该很详细了,本来想说点什么的,但是感觉说不出话……各位要是有什么问题,记得提出issue,我会尽力解答 218 | 219 | 220 | 接下来是另外两个函数: 221 | 222 | ``` 223 | def change_pattern(mode,pattern_matrix): 224 | #先更改到布局模式 225 | mode.switchtolayout() 226 | 227 | #这里定义了一个双向字典,换成人话来说就是定义了一个一对一的表,通过这个表我们能够查询1,0和对对应材料的关系 228 | pattern_dic=bidict({ 229 | "Si (Silicon) - Palik":1, 230 | "etch":0 231 | }) 232 | 233 | # 两个for循环嵌套,更改每个离散网格内部的材料,(这里没想到一个更优美的解决方案……) 234 | for row in range(pattern_matrix.shape[0]): 235 | for column in range(pattern_matrix.shape[1]): 236 | mode.select("666::"+str(row)+"r"+str(column)+"c") 237 | 238 | #可以通过这种方式获取对象的属性 239 | pix = mode.getObjectBySelection() 240 | material_name=pix.material 241 | 242 | #根据目标矩阵查询是否需要更改对象的材料 243 | if pattern_dic[material_name]!=pattern_matrix[row][column]: 244 | pix.material=pattern_dic.inverse[pattern_matrix[row][column]] 245 | 246 | def get_result(mode): 247 | #这里的.squeeze()方法意思是删除多余的维度,如把(2,3,1,3)变为(2,3,3),方便后续处理 248 | t1 = mode.getresult("T1", "E")["E"].squeeze() 249 | t2 = mode.getresult("T2", "E")["E"].squeeze() 250 | #这里a,b是两个监视器的电场幅值,即xyz方向的平方相加开根 251 | a = np.sqrt(np.sum(np.power(np.abs(t1), 2), axis=1)) 252 | b = np.sqrt(np.sum(np.power(np.abs(t2), 2), axis=1)) 253 | return a,b 254 | 255 | ``` 256 | 257 | 应该挺简单的……也说不出什么话…… 258 | 259 | ## 结语 260 | 261 | 根据lumerical官方的说法,python中的方法和他们自带的脚本语言使用方式和命名都相同,如python中的`fdtd.addpower()`对应脚本语言中的`addpower;` https://support.lumerical.com/hc/en-us/articles/360034404534-addpower 262 | 263 | 更详细的方法查询可以参考[关于函数、方法的查询](附录.md#关于函数、方法的查询) 264 | 265 | -------------------------------------------------------------------------------- /docs/前言.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 3 | 这个仓库的作用主要有两个: 4 | 1. 记录、备份lumerical 与python交互的技巧和笔记。 5 | 2. 整理组内常用的拓扑优化算法,并用py重构,以提升工作效率。 6 | * 将常用函数整合,附以重要的参数和例子说明 7 | 8 | 9 | 剩下的还没想好,欢迎提issue和pr。 -------------------------------------------------------------------------------- /docs/安装.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | 安装主要分为三个部分: 4 | 1. lumerical的安装 5 | 2. python 环境的安装 6 | 3. python 联合 lumerical的api的初始环境设置 7 | 8 | 9 | ## lumerical 10 | 根据lumerical官方的说法: https://support.lumerical.com/hc/en-us/articles/360037824513-Python-API-overview 11 | 12 | 13 | 14 | 为了能够正常使用python的接口,我们需要三个条件: 15 | 16 | 1. 自动化python api证书 17 | 2. 2019a R3 或者更新的lumerical 软件版本 18 | 3. 在Linux上:为支持的Linux系统运行bashshell的gnome终端 19 | 20 | ***其中最主要的,就是需要2019a R3版本以上的软件。*** 21 | 22 | 这里不会提供下载方式,可以在大学内部的网站进行下载:(蝴蝶、byr什么的) 23 | 24 | 安装并激活之后,可以从下图中查看python api是否激活(这里以mode为例): 25 | 26 | ![](_images/2021-01-04-17-29-03.png) 27 | 28 | 29 | 30 | ## python 31 | 32 | python的环境配置有很多种,每个人的习惯都不同,所以这里仅简要写一下个人配置的环境 33 | 34 | 本人的环境是:win10 + miniconda + pycharm + jupyter notebook 35 | 36 | 解释一下,做大型工程时,主要使用pycharm,做小型测试和数据可视化的时候,则主要使用jupyter。 37 | 38 | 39 | ## python+lumerical环境结合 40 | 41 | lumerical公司提供的python api接口为软件自带的一个py文件,我们只需要在使用中能够导入就行。 42 | 43 | 假设你的lumerical安装路径在C盘,则python文件的路径为"C:\Program Files\Lumerical\v202\api\python\lumapi.py" 44 | > 路径中的v202是版本号,各位看需进行更改 45 | 46 | 那么如何将这个文件导入呢? 47 | 48 | 这里提供一个一劳永逸的方法:自定义一个pth文件,这样python就能直接`import lumapi`了 49 | 50 | 方法如下: 51 | 52 | 假设你的lumapi安装在c盘,miniconda中的虚拟环境叫做fdtd,并安装在g盘,那么 53 | 54 | 1. 在`G:\miniconda\envs\fdtd\Lib\site-packages`路径下新建`lumapi.pth`文件,内容为`C:\Program Files\Lumerical1\v202\api\python` 55 | 2. 在编程环境中激活虚拟环境fdtd,输入 56 | 57 | ``` 58 | import sys 59 | print('\n'.join(sys.path)) 60 | 61 | G:\miniconda\envs\fdtd\python38.zip 62 | G:\miniconda\envs\fdtd\DLLs 63 | G:\miniconda\envs\fdtd\lib 64 | G:\miniconda\envs\fdtd 65 | G:\miniconda\envs\fdtd\lib\site-packages 66 | G:\Program Files\Lumerical1\v202\api\python 67 | G:\miniconda\envs\fdtd\lib\site-packages\win32 68 | G:\miniconda\envs\fdtd\lib\site-packages\win32\lib 69 | G:\miniconda\envs\fdtd\lib\site-packages\Pythonwin 70 | ``` 71 | 72 | 就能够看到fdtd这个虚拟环境已经成功将lumerical的python路径导入了。 73 | 74 | 75 | ## 结尾 76 | 如果上述安装全都没有出问题,现在就能够开始仿真了。 77 | 78 | 打开你熟悉的py编程环境,尝试输入一下代码并保存运行,看看效果吧: 79 | 80 | ``` 81 | import lumapi 82 | 83 | mode = lumapi.MODE() 84 | mode.addrect(x=0, y=0.0, z=-1.11e-6,x_span=2e-5,y_span=1e-5,z_span=2e-6,name="box",material="SiO2 (Glass) - Palik") 85 | input() 86 | ``` 87 | 88 | **注意! lumapi依赖于numpy库,所以如果导入报错了,则需要在环境中另外安装numpy!** 89 | 90 | 接下来会写如何使用python api完全代替图形化的操作,包括多线程、会话管理这些。 -------------------------------------------------------------------------------- /docs/测试.md: -------------------------------------------------------------------------------- 1 | # latex测试 2 | $$ 3 | \left(\begin{array}{l} c t^{\prime} \\ x^{\prime} \\ y^{\prime} \\ z^{\prime} \end{array}\right)=\left(\begin{array}{cccc} \gamma & -\gamma \beta & 0 & 0 \\ -\gamma \beta & \gamma & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right)\left(\begin{array}{l} c t \\ x \\ y \\ z \end{array}\right) 4 | $$ 5 | 6 | 7 | # 代码copy测试 8 | 9 | ``` 10 | print("hello python") 11 | 12 | ``` -------------------------------------------------------------------------------- /docs/附录.md: -------------------------------------------------------------------------------- 1 | # 关于python中的包管理 2 | 3 | python中的包管理主要有两种工具,分别是pip和conda,接下来分别介绍: 4 | 5 | * conda:其中conda为anaconda或miniconda特有的包管理工具。 6 | * 优点:除了能够安装普通python包之外,还能够一并安装依赖的其他语言的二进制文件。 7 | * 缺点:有些包是社区维护,并没有更新到最新版;有些包没有。 8 | * 推荐使用方式:安装numpy、pytorch、scipy这些科学计算包时 9 | 10 | * pip:python自带的官方包管理工具。 11 | * 优点:官方维护,一些比较小众的工具包在上面可以找到,conda则没有 12 | * 缺点:当包依赖于其他外部库时、或者有平台限制时,可能会安装失败(TensorFlow这种……) 13 | * 推荐使用方式:bidict、faker这些工具轮子库 14 | 15 | ## 更换下载源 16 | * conda:[清华官方说明](https://mirror.tuna.tsinghua.edu.cn/help/anaconda/) 17 | 18 | * pip :本人比较懒,只有在每次conda装不上的时候才使用pip,所以每次pip的时候都手动指定安装的代理,这里就用例子来说明: 19 | 20 | ``` 21 | # 例如我们要安装bidict 22 | pip install bidict -i https://pypi.tuna.tsinghua.edu.cn/simple 23 | ``` 24 | 25 | ## 包安装方式 26 | * conda:在更改过软件源之后,打开命令行(cmd) 27 | 28 | ``` 29 | #激活对应的虚拟环境 30 | conda activate fdtd 31 | 32 | #开始安装 33 | conda install matplotlib 34 | ``` 35 | 36 | * pip: 37 | 38 | ``` 39 | # 例如我们要安装bidict 40 | pip install bidict -i https://pypi.tuna.tsinghua.edu.cn/simple 41 | ``` 42 | 43 | # 关于函数、方法的查询 44 | 根据lumerical官方的说法,python中的方法和他们自带的脚本语言使用方式和命名都相同,如python中的`fdtd.addpower()`对应脚本语言中的`addpower;` https://support.lumerical.com/hc/en-us/articles/360034404534-addpower 45 | 46 | 但还是存在一些微小的差异,那么我们如何查询呢? 47 | 48 | 我们可以借鉴脚本语言中的`?set`命令 https://support.lumerical.com/hc/en-us/articles/360034928773-set-Script-command 49 | 50 | 举个例子:我们想设置监视器T1的长宽,但是不知道对应的变量名字叫啥,我们就可以: 51 | 52 | ``` 53 | #我们以例程中的结果为例,大家可以将例程中的代码放在jupyter中跑,以免跑完后程序关闭 54 | 55 | mode.select("T1") #选择T1 56 | print(mode.set()) #打印出能够设置的参数 57 | 58 | #以下是对应的输出 59 | Nyquist limit 60 | actual sampling 61 | apodization 62 | apodization center 63 | apodization freq width 64 | apodization time width 65 | custom frequency samples 66 | delta 67 | desired sampling 68 | down sample X 69 | down sample Y 70 | down sample Z 71 | down sample time 72 | enabled 73 | frequency center 74 | frequency points 75 | frequency span 76 | maximum frequency 77 | maximum wavelength 78 | min sampling per cycle 79 | minimum frequency 80 | minimum wavelength 81 | monitor type 82 | name 83 | output Ex 84 | output Ey 85 | output Ez 86 | output Hx 87 | output Hy 88 | output Hz 89 | output Px 90 | output Py 91 | output Pz 92 | output power 93 | override advanced global monitor settings 94 | override global monitor settings 95 | partial spectral average 96 | record data in pml 97 | sample spacing 98 | spatial interpolation 99 | standard fourier transform 100 | total spectral average 101 | type 102 | use relative coordinates 103 | use source limits 104 | use wavelength spacing 105 | wavelength center 106 | wavelength span 107 | x 108 | x max 109 | x min 110 | x span 111 | y 112 | y max 113 | y min 114 | y span 115 | z 116 | z max 117 | z min 118 | z span 119 | ``` 120 | 121 | 能看到有x,y,z的设置,于是我们就能这样设置参数了: 122 | 123 | ``` 124 | mode.addpower(properties=OrderedDict([("name", "T1"), ("monitor type", "2D X-normal"), 125 | ("x", 1.45e-6), ("y", 0.75e-6),("z",0), 126 | ("y span", 0.5e-6),("z span",0.4e-6), 127 | ("override global monitor settings", True),("frequency points",1)])) 128 | ``` -------------------------------------------------------------------------------- /src/gen_data/main.py: -------------------------------------------------------------------------------- 1 | import lumapi 2 | import numpy as np 3 | from collections import OrderedDict 4 | import os 5 | from bidict import bidict 6 | 7 | 8 | row_num = 10 9 | column_num = 10 10 | workers = 2 11 | def init_base(mode,size=(2,2)): 12 | mode.switchtolayout() 13 | # 基底生成 14 | mode.importmaterialdb("fdtd_files/material.mdf") 15 | mode.addrect(x=0, y=0.0, z=-1.11e-6,x_span=2e-5,y_span=1e-5,z_span=2e-6,name="box",material="SiO2 (Glass) - Palik") 16 | mode.addrect(x=0, y=0.0, z=0,x_span=2.6e-6,y_span=2.6e-6,z_span=0.22e-6,name="si",material="si") 17 | mode.addrect(x=-5.15e-6, y=0.0, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="in", 18 | material="si") 19 | mode.addrect(x=5.15e-6, y=0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out1", 20 | material="si") 21 | mode.addrect(x=5.15e-6, y=-0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out2", 22 | material="si") 23 | mode.addmesh(x=0, y=0, z=0, x_span=2.6e-6, y_span=2.6e-6, z_span=0.22e-6, name="mesh", 24 | dx=0.02e-6,dy=0.02e-6,dz=0.02e-6,) 25 | mode.addvarfdtd(x=0, y=0, z=0,x_span=4e-6, y_span=4e-6, z_span=0.8e-6,simulation_time=1000e-15,x0=-1.48565e-6) 26 | 27 | source_props = OrderedDict([("name", "source"), ("injection axis", "x"), 28 | ("x", -1.7e-6), ("y", 0),("y span", 2e-6), 29 | ("selected mode number",2), 30 | ("center wavelength",1.5e-6),("wavelength span",0.01e-6), 31 | ("optimize for short pulse", 1) 32 | ]) 33 | mode.addmodesource(properties=source_props) 34 | 35 | mode.addpower(properties=OrderedDict([("name", "T1"), ("monitor type", "2D X-normal"), 36 | ("x", 1.45e-6), ("y", 0.75e-6),("z",0), 37 | ("y span", 0.75e-6),("z span",0.4e-6), 38 | ("override global monitor settings", True),("frequency points",1)])) 39 | mode.addmodeexpansion(properties=OrderedDict([ 40 | ("name", "M1"), 41 | ("x", 1.65e-6), 42 | ("y", 0.75e-6), 43 | ("y span", 0.75e-6), 44 | ])) 45 | mode.setexpansion("input", "T1") 46 | 47 | mode.addpower(properties=OrderedDict([("name", "T2"), ("monitor type", "2D X-normal"), 48 | ("x", 1.45e-6), ("y", -0.75e-6),("z",0), 49 | ("y span", 0.75e-6),("z span",0.4e-6), 50 | ("override global monitor settings", True),("frequency points",1)])) 51 | 52 | mode.addmodeexpansion(properties=OrderedDict([ 53 | ("name", "M2"), 54 | ("x", 1.65e-6), 55 | ("y", 0.75e-6), 56 | ("y span", 0.75e-6), 57 | ])) 58 | mode.setexpansion("input", "T2") 59 | 60 | mode.addpower(properties=OrderedDict([("name", "all"), ("monitor type", "2D Z-normal"), 61 | ("x", 0), ("y", 0), ("z", 0), 62 | ("x span", 2.6e-6), ("y span", 2.6e-6), 63 | ("override global monitor settings", True), ("frequency points", 1)])) 64 | # pattern生成 65 | rows, columns = size[0], size[1] 66 | mode.addstructuregroup(name="666") 67 | x_span = 2.6e-6 / columns 68 | y_span = 2.6e-6 / rows 69 | for row in range(rows): 70 | for column in range(columns): 71 | mode.addrect(x=-1.3e-6 + x_span / 2 + column * x_span, x_span=x_span, 72 | y=1.3e-6 - y_span / 2 - row * y_span, y_span=y_span, 73 | z=0, z_span=0.22e-6, name=str(row) + "r" + str(column) + "c", 74 | material="etch") 75 | mode.addtogroup("666") 76 | 77 | def change_pattern_(old_pattern_matrix=np.zeros([row_num,column_num])): 78 | def change(mode,new_pattern_matrix): 79 | nonlocal old_pattern_matrix 80 | mode.switchtolayout() 81 | pattern2change = np.argwhere(old_pattern_matrix!=new_pattern_matrix) 82 | pattern_dic = bidict({ 83 | "si": 1, 84 | "etch": 0 85 | }) 86 | for row,column in pattern2change: 87 | mode.select("666::"+str(row)+"r"+str(column)+"c") 88 | pix = mode.getObjectBySelection() 89 | pix.material=pattern_dic.inverse[new_pattern_matrix[row][column]] 90 | old_pattern_matrix = new_pattern_matrix 91 | return change 92 | 93 | def fom(mode): 94 | t1 = mode.getresult("T1", "E")["E"].squeeze() 95 | t2 = mode.getresult("T2", "E")["E"].squeeze() 96 | a = np.sqrt(np.sum(np.power(np.abs(t1), 2), axis=1)) 97 | b=np.sqrt(np.sum(np.power(np.abs(t2), 2), axis=1)) 98 | return (a-b).max() 99 | 100 | 101 | mode = lumapi.MODE() 102 | init_base(mode, size=(row_num, column_num)) 103 | mode.save("fdtd_files/base"+str(row_num)+"_"+str(column_num)+".lms") 104 | change_pattern = change_pattern_() 105 | fileds=[] 106 | pattern=[] 107 | for i in range(2): 108 | for i in range(workers): 109 | pattern_matrix = np.random.randint(0, 2, (row_num // 2, column_num)) 110 | pattern_matrix = np.concatenate([np.flip(pattern_matrix, axis=0), pattern_matrix], axis=0) 111 | pattern.append(pattern_matrix) 112 | change_pattern(mode, pattern_matrix) 113 | currentfilename = os.getcwd() + "/fdtd_files/temp/temp_" + str(i) + ".lms" 114 | mode.save(currentfilename) 115 | mode.addjob(currentfilename) 116 | 117 | mode.runjobs() 118 | 119 | for i in range(workers): 120 | currentfilename = os.getcwd() + "/fdtd_files/temp/temp_" + str(i) + ".lms" 121 | mode.load(currentfilename) 122 | t1 = mode.getresult("M1", "expansion for input")["T_forward"].squeeze() 123 | fileds.append( 124 | np.einsum("ijk->jik",np.concatenate( 125 | [mode.getresult("all", "E")["E"].squeeze(), mode.getresult("all", "H")["H"].squeeze()] 126 | ,axis=2))[:51,:]) 127 | 128 | 129 | 130 | fileds=np.array(fileds) 131 | pattern = np.array(pattern) 132 | a=input() 133 | np.savez("data/data.npy",pattern=pattern, fileds=fileds) 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/material.mdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Photonic-AI-Communication/lumerical-python-script/ba1b44ea665e7b0ec347970d67f1dd18bd2170f7/src/material.mdf -------------------------------------------------------------------------------- /src/transpose/gen_data.py: -------------------------------------------------------------------------------- 1 | from initbase import init_base,change_pattern,fom 2 | import lumapi 3 | import numpy as np 4 | from collections import OrderedDict 5 | import os 6 | from bidict import bidict 7 | 8 | row_num = 5 9 | column_num = 5 10 | mode = lumapi.MODE() 11 | init_base(mode, size=(row_num, column_num)) 12 | mode.save("fdtd_files/base"+str(row_num)+"_"+str(column_num)+".lms") 13 | 14 | pattern_matrix = np.random.randint(0, 2, (row_num, column_num)) 15 | change_pattern(mode,pattern_matrix) 16 | mode.run() 17 | best_result=fom(mode) 18 | 19 | t1 = mode.getresult("M1","expansion for input")["T_forward"].squeeze() 20 | print(t1) 21 | a=input() -------------------------------------------------------------------------------- /src/transpose/initbase.py: -------------------------------------------------------------------------------- 1 | import lumapi 2 | import numpy as np 3 | from collections import OrderedDict 4 | import os 5 | from bidict import bidict 6 | 7 | 8 | def init_base(mode,size=(2,2)): 9 | mode.switchtolayout() 10 | # 基底生成 11 | mode.importmaterialdb("fdtd_files/material.mdf") 12 | mode.addrect(x=0, y=0.0, z=-1.11e-6,x_span=2e-5,y_span=1e-5,z_span=2e-6,name="box",material="SiO2 (Glass) - Palik") 13 | mode.addrect(x=0, y=0.0, z=0,x_span=2.6e-6,y_span=2.6e-6,z_span=0.22e-6,name="si",material="si") 14 | mode.addrect(x=-5.15e-6, y=0.0, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="in", 15 | material="si") 16 | mode.addrect(x=5.15e-6, y=0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out1", 17 | material="si") 18 | mode.addrect(x=5.15e-6, y=-0.75e-6, z=0, x_span=7.7e-6, y_span=0.5e-6, z_span=0.22e-6, name="out2", 19 | material="si") 20 | mode.addmesh(x=0, y=0, z=0, x_span=2.6e-6, y_span=2.6e-6, z_span=0.22e-6, name="mesh", 21 | dx=0.02e-6,dy=0.02e-6,dz=0.02e-6,) 22 | mode.addvarfdtd(x=0, y=0, z=0,x_span=4e-6, y_span=4e-6, z_span=0.8e-6,simulation_time=1000e-15,x0=-1.48565e-6) 23 | 24 | source_props = OrderedDict([("name", "source"), ("injection axis", "x"), 25 | ("x", -1.7e-6), ("y", 0),("y span", 2e-6), 26 | ("selected mode number",2), 27 | ("center wavelength",1.5e-6),("wavelength span",0.01e-6), 28 | ("optimize for short pulse", 1) 29 | ]) 30 | mode.addmodesource(properties=source_props) 31 | 32 | mode.addpower(properties=OrderedDict([("name", "T1"), ("monitor type", "2D X-normal"), 33 | ("x", 1.45e-6), ("y", 0.75e-6),("z",0), 34 | ("y span", 0.75e-6),("z span",0.4e-6), 35 | ("override global monitor settings", True),("frequency points",1)])) 36 | mode.addmodeexpansion(properties=OrderedDict([ 37 | ("name", "M1"), 38 | ("x", 1.65e-6), 39 | ("y", 0.75e-6), 40 | ("y span", 0.75e-6), 41 | ])) 42 | mode.setexpansion("input", "T1") 43 | 44 | mode.addpower(properties=OrderedDict([("name", "T2"), ("monitor type", "2D X-normal"), 45 | ("x", 1.45e-6), ("y", -0.75e-6),("z",0), 46 | ("y span", 0.75e-6),("z span",0.4e-6), 47 | ("override global monitor settings", True),("frequency points",1)])) 48 | 49 | mode.addmodeexpansion(properties=OrderedDict([ 50 | ("name", "M2"), 51 | ("x", 1.65e-6), 52 | ("y", 0.75e-6), 53 | ("y span", 0.75e-6), 54 | ])) 55 | mode.setexpansion("input", "T2") 56 | 57 | mode.addpower(properties=OrderedDict([("name", "all"), ("monitor type", "2D Z-normal"), 58 | ("x", 0), ("y", 0), ("z", 0), 59 | ("x span", 2.6e-6), ("y span", 2.6e-6), 60 | ("override global monitor settings", True), ("frequency points", 1)])) 61 | # pattern生成 62 | rows, columns = size[0], size[1] 63 | mode.addstructuregroup(name="666") 64 | x_span = 2.6e-6 / columns 65 | y_span = 2.6e-6 / rows 66 | for row in range(rows): 67 | for column in range(columns): 68 | mode.addrect(x=-1.3e-6 + x_span / 2 + column * x_span, x_span=x_span, 69 | y=1.3e-6 - y_span / 2 - row * y_span, y_span=y_span, 70 | z=0, z_span=0.22e-6, name=str(row) + "r" + str(column) + "c", 71 | material="etch") 72 | mode.addtogroup("666") 73 | 74 | def change_pattern(mode,pattern_matrix): 75 | mode.switchtolayout() 76 | pattern_dic=bidict({ 77 | "si":1, 78 | "etch":0 79 | }) 80 | for row in range(pattern_matrix.shape[0]): 81 | for column in range(pattern_matrix.shape[1]): 82 | mode.select("666::"+str(row)+"r"+str(column)+"c") 83 | pix = mode.getObjectBySelection() 84 | material_name=pix.material 85 | if pattern_dic[material_name]!=pattern_matrix[row][column]: 86 | pix.material=pattern_dic.inverse[pattern_matrix[row][column]] 87 | 88 | def fom(mode): 89 | t1 = mode.getresult("T1", "E")["E"].squeeze() 90 | t2 = mode.getresult("T2", "E")["E"].squeeze() 91 | a = np.sqrt(np.sum(np.power(np.abs(t1), 2), axis=1)) 92 | b=np.sqrt(np.sum(np.power(np.abs(t2), 2), axis=1)) 93 | return (a-b).max() 94 | 95 | --------------------------------------------------------------------------------