第二章:仿真环境搭建——Lumerical/COMSOL安装与配置、Python API接口调用、脚本化仿真流程
说实话,很多做硅光的朋友一开始都栽在环境搭建上。软件装好了跑不通,API调不通,脚本写好了报错——这些坑我全踩过。今天咱们就把这块硬骨头啃下来。
2.1 Lumerical与COMSOL的安装与配置
先说说这两个工具的区别。Lumerical擅长波导、耦合器这类周期性结构,FDTD算法跑得快。COMSOL则强在多物理场耦合,比如热光效应、电光调制。我个人习惯是:做无源器件用Lumerical,做有源器件或热分析用COMSOL。
安装要点:
- Lumerical 2021R2+:建议用2021R2以上版本,Python API更稳定。安装时记得勾选"Python API Support"。
- COMSOL 6.0+:安装时选择"LiveLink for MATLAB"和"Python API",这两个模块默认不装,得手动勾选。
- 许可证配置:Lumerical用浮动license,COMSOL用节点锁。我遇到过license服务器挂了导致整个团队停摆的情况,所以建议配个备用license。
避坑指南:我曾经在Windows上装Lumerical时,Python路径没配好,结果API死活调不通。后来发现是系统环境变量里Python路径被Anaconda覆盖了。解决办法:把Lumerical的Python路径加到系统PATH最前面。
2.2 Python API接口调用实战
环境配好了,咱们来写代码。先看Lumerical的Python API怎么用。
# 导入Lumerical API
import lumapi
import numpy as np
# 启动FDTD引擎
fdtd = lumapi.FDTD()
# 创建一个简单的波导结构
fdtd.addrect()
fdtd.set("name", "waveguide")
fdtd.set("x", 0)
fdtd.set("y", 0)
fdtd.set("z", 0)
fdtd.set("x span", 0.5e-6) # 500nm宽
fdtd.set("y span", 0.22e-6) # 220nm厚
fdtd.set("z span", 1e-6) # 1um长
# 设置材料
fdtd.set("material", "Si (Silicon) - Palik")
# 添加光源
fdtd.addmode()
fdtd.set("name", "source")
fdtd.set("x", -0.5e-6)
fdtd.set("injection axis", "x-axis")
# 运行仿真
fdtd.run()
# 提取结果
T = fdtd.getresult("monitor", "T")
print(f"透射率: {T['T']:.4f}")
# 关闭引擎
fdtd.close()
这段代码看着简单,但有几个坑要注意。第一,addrect()之后一定要set("name"),不然后面引用会乱。第二,单位全是米,别写成微米了——我刚开始就犯过这个错,算出来的结果差了1000倍。
再看COMSOL的Python API。说实话,COMSOL的API比Lumerical复杂一些,但功能更强大。
# 导入COMSOL API
import mph
import numpy as np
# 启动COMSOL客户端
client = mph.start()
model = client.create("silicon_photonic")
# 创建几何
model.geom("geom1").create("waveguide", "Block")
model.geom("geom1").feature("waveguide").set("size", [0.5e-6, 0.22e-6, 1e-6])
model.geom("geom1").feature("waveguide").set("pos", [-0.25e-6, -0.11e-6, -0.5e-6])
# 设置材料
model.material("mat1").create("Si", "Material")
model.material("mat1").property("refractive_index").set("n", 3.48)
# 添加物理场
model.physics("emw").create("port1", "Port", 1)
model.physics("emw").feature("port1").set("port_type", "Rectangular")
# 网格划分
model.mesh("mesh1").create("mesh1", "Free Tetrahedral")
model.mesh("mesh1").feature("size").set("custom", True)
model.mesh("mesh1").feature("size").set("hmax", 0.05e-6)
# 求解
model.solve("study1")
# 提取结果
result = model.evaluate("emw.normE")
print(f"电场强度: {result:.4f} V/m")
# 关闭
client.close()
小技巧:COMSOL的API文档藏在安装目录下的doc/mph文件夹里。我第一次找这个文档找了半小时,后来直接写了个脚本自动打开它。
2.3 脚本化仿真流程
手动点鼠标做仿真,一次两次还行。但参数优化时,可能要跑几百次仿真。这时候脚本化就是救命稻草。
我一般把仿真流程拆成三步:
- 参数定义:把所有可调参数集中到一个字典里
- 仿真循环:用for循环或并行计算跑参数扫描
- 结果收集:自动保存结果到CSV或HDF5文件
来看一个完整的脚本化例子:
import lumapi
import numpy as np
import pandas as pd
from tqdm import tqdm
# 第一步:参数定义
params = {
"width": np.linspace(0.4e-6, 0.6e-6, 10), # 波导宽度扫描
"gap": np.linspace(0.1e-6, 0.3e-6, 10), # 耦合间距扫描
"length": 10e-6 # 固定长度
}
# 第二步:仿真循环
results = []
for w in tqdm(params["width"]):
for g in params["gap"]:
# 创建新仿真
fdtd = lumapi.FDTD()
# 构建结构
fdtd.addrect()
fdtd.set("name", "wg1")
fdtd.set("x span", w)
fdtd.set("y span", 0.22e-6)
fdtd.set("z span", params["length"])
fdtd.addrect()
fdtd.set("name", "wg2")
fdtd.set("x span", w)
fdtd.set("y span", 0.22e-6)
fdtd.set("z span", params["length"])
fdtd.set("x", w + g) # 偏移形成耦合区
# 运行
fdtd.run()
# 提取结果
T = fdtd.getresult("monitor", "T")
# 保存
results.append({
"width": w,
"gap": g,
"transmission": T['T']
})
fdtd.close()
# 第三步:结果保存
df = pd.DataFrame(results)
df.to_csv("coupler_scan_results.csv", index=False)
print("仿真完成,结果已保存")
这段代码跑起来可能要几个小时。我建议先用粗网格跑一遍,找到大概的最优区域,再加密网格精细扫描。这样能省下至少一半时间。
核心要点:
- Lumerical API用
lumapi包,COMSOL用mph包 - 参数扫描时,先粗后细,别一上来就高精度
- 结果一定要自动保存,别指望手动记录
- 并行计算可以用Python的
multiprocessing,但注意license限制
2.4 知识体系总览
下面这张图把本章的核心逻辑串起来了。你想想看,从环境搭建到API调用,再到脚本化流程,其实是一条线:工具→接口→自动化。
嗯,这张图把咱们今天讲的内容串起来了。从左到右,从环境到脚本,每一步都环环相扣。你想想看,如果环境没配好,后面API调得再熟也没用。所以别嫌麻烦,把基础打牢。
我的经验:刚开始做脚本化仿真时,我总想一步到位写个完美的脚本。结果调试花了两天,还不如手动点鼠标快。后来学乖了:先写个能跑的版本,再逐步优化。记住,能跑的代码比完美的代码更有价值。
公众号:蓝海资料掘金营,微信deep3321