最近收拾硬盘,翻出来一堆COMSOL模型文件,仔细一数,居然有40多个mph。这些都是我当初对照一本光子晶体专著一点点复现的,覆盖一维多层膜、二维周期柱阵列,再到三维反蛋白石和复杂波导结构。当时做这个项目,没指望能出什么论文,就是觉得书里那些能带图太漂亮了,光看公式实在不过瘾,想亲眼看着它们从求解器里跑出来。结果这一跑,就入了坑。如果你也是刚接触光子晶体,或者在用COMSOL 5.6做微纳光子学的仿真,这个项目应该能帮你少走不少弯路。这套文件几乎就是一个现成的案例库:打开、看设置、改参数、重新算,一连串动作都很直接。
1. 项目缘起:把一本厚书“跑起来”是个什么概念
1.1 为什么要复现而不是只看公式
光子晶体这门课最大的门槛,不是量子力学,而是“看不见”。介质折射率周期排列之后,光会怎么走、哪些频率会被挡住,光靠脑子里推导二维平面的布洛赫波,很难建立直觉。书里的公式当然严谨,但公式是抽象的,尤其到了三维、到了TM/TE模式分裂、到了带隙边缘的场分布,光看文字根本想象不出形状。
我的习惯很笨:对着书上的图,把参数猜出来,然后在COMSOL里重新搭一遍。所谓复现,不是简单照着mph文件跑一遍,而是要把书中的一段话转成一个可计算的模型。比如书上说“正方晶格圆柱,半径0.2a,折射率3.4”,那你在软件里就得问自己:a是多少?工作频率范围怎么设?k点路径是从Γ到X还是从M回Γ?这些问题不亲手解决,看十遍书都白搭。
还有一个现实原因:很多学校没有昂贵的实验平台,但一台普通电脑就能算能带。COMSOL 5.6对硬件要求不算苛刻,16GB内存跑二维案例绰绰有余。所以复现成了性价比极高的学习手段,既是理论课作业,又是一份能反复调用的数字资产。
1.2 40多个mph文件的构成
这套项目里的mph文件不是乱堆的,而是按维度分层的。一维案例大概有十几个,主要处理多层膜结构的反射率和一维光子带隙;二维案例是数量最多的部分,包括三角晶格、正方晶格、蜂窝晶格里的不同TE/TM模能带;三维案例最少,但每一个都足够有分量,涉及反蛋白石结构、三维波导耦合、以及完整的布里渊区路径扫描。
每一个文件的命名,我都尽量保留书中的章节号和结构关键词,比如“ch3_2D_square_TE_band.mph”这种格式。这样做的好处是,当成千上万个文件堆在一起,你想回头找“那个二维蜂窝晶格的TM模案例”,靠名字就能筛出来。
这些文件的共同特点是:几何都比较简单,难点全在物理设置上。圆柱、球形、矩形这些基础几何画起来很快,但周期边界的配对、特征值搜索范围的设定、网格与频率的匹配,才是决定结果能否收敛到正确能带的关键。
1.3 一、二、三维案例的难度曲线
一维案例是热身。几何就是一堆长方形叠起来,边界条件简化到极致,网格用映射就行,几秒钟就能算出好几条带隙。缺点是实际感弱,因为真实空间里总有两个横向方向没有被周期化处理,但用来理解“带隙是什么”已经是满分答案。
二维案例是主战场。以正方晶格为例,一个边长a的正方形晶胞,中心放一根圆柱,加上Floquet周期边界,扫一条不可约布里渊区路径,能带图就能出来。这里的难点是TE和TM模式的区分,以及对周期边界条件中相位关系的理解。我在这层花了最多时间,因为很多微妙的结果差异都源于边界条件设错了。
三维案例是硬骨头。网格稍微粗一点,特征值偏移会大得惊人;网格稍微密一点,内存又报警。三维反蛋白石或蛋白石结构的计算,需要提前规划自由度总数,通常我只取第一布里渊区的几条高对称线来算,不会做全空间扫描。三维案例不适合入门,但它是检验你前两维知识有没有学透的试金石。
2. 能带计算的底层逻辑与COMSOL中的对应关系
2.1 光子晶体能带到底在解什么方程
不管是一维、二维还是三维,能带计算的核心都是求解电磁场的本征值问题。介质中无源、无损耗、线性材料的前提下,电磁波满足矢量波动方程:
∇×(∇×E) - k0²·εr·E = 0
这里的k0是真空波矢,εr是相对介电常数。问题的关键是介电常数在空间上周期分布,所以方程的解不再是简单的平面波,而是布洛赫波的形式:E(r) = u(r)·e^{j·k·r}。其中u(r)和晶格同周期,k是波矢,跑了不起眼的“相位”作用,实际上决定了整个能带结构。
把它和吉他弦类比就很好懂:吉他弦的振动频率取决于弦长、张力和单位长度质量,是一组离散的本征频率。光子晶体也是类似,材料周期分布相当于给电磁波设了“驻波条件”,只有特定的频率和特定的波矢组合才能存在。能带图说白了就是:给一个k,算出所有允许的频率,连起来就成了带。
在COMSOL里,这一步通常用“电磁波、频域”接口下的“特征值”研究来完成。特征值不是时间t,而是本征频率f。你给出一堆k值,软件会针对每个k输出若干个本征频率,这些点连成线就是能带。
2.2 Floquet周期边界条件:周期性假设的直接体现
要在一个有限大小的几何里模拟无限周期结构,必须靠周期边界条件。COMSOL中叫Floquet周期边界条件,本质上就是布洛赫定理的边界形式。它要求一对边界上的场满足:
E_dest = E_source · e^{j·k·(r_dest - r_source)}
其中r_dest和r_source是目标边界和源边界上的位置向量,k就是你要扫描的波矢。这个相位乘子是整个能带计算的灵魂。很多人算出来的能带是错位的,跳来跳去,基本都是因为这个相位关系设置反了,或者源边界和目标边界选反了。
在模型里,设置Floquet边界时,软件会让你输入“波矢”的各个分量,通常是用全局参数定义,例如k_x = kx_scan、k_y = ky_scan。这些参数可以在辅助扫描中被循环赋值,从而完成整条布里渊区路径的扫描。
注意一维、二维、三维需要配对的边界对数不同。一维只需一对;二维需要两对(当然如果你只建一半再加对称条件,可以只设一对);三维要三对。每对边界在设置时都要确认“源边界”和“目标边界”的高亮方向,有一个方向反了,计算结果就会完全不可信。
2.3 特征值搜索模式与“色散关系”的关系
能带图本质就是色散关系,即频率与波矢的关系。COMSOL的特征值求解器通常允许你设定“搜索基准点”和“搜索特征值数量”。这一点特别关键:如果搜索范围太小,高频模式会丢失,能带图就会少几条带;搜索范围太大,又会把很多非物理的伪特征值也捞进来。
我的经验是,先算一个k=0的参考点,观察前几个特征值大概落在什么频率区间,再根据需求把搜索范围缩窄到感兴趣区域。例如想算可见光波段,把搜索范围设在0到6×10^14 Hz之间,目标数量设为8到12条带,往往就有不错的分辨率。之后扫描k时,依赖“参数化扫描”配合“重新使用上一步的解作为初值”,能明显提高扫带效率。
色散关系这个名字听起来复杂,实际上你只需要记住一件事:横轴是k,纵轴是归一化频率a/λ。这里的a是晶格常数,λ是真空波长。归一化后的能带图与具体尺寸无关,只和结构占空比、折射率对比度有关,这也是不同论文之间能相互对比的原因。
2.4 关于“弱形式求解色散光子晶体能带”的方案
标准ewfd接口能处理大多数光子晶体问题,但碰到材料介电常数随频率变化(即色散材料)时,标准特征值公式会变得别扭,因为εr(ω)使问题不再是标准的线性特征值问题。这时需要借助弱形式方程。
COMSOL的弱形式解法,通俗讲就是把你手中的偏微分方程先变形成积分形式,再告诉软件每个项应该在哪个域里做数值积分。对于色散光子晶体,常见的做法是把波动方程改写成关于u(r)的广义特征值方程,并把色散D(electric displacement field)作为额外的状态变量引入。这样一来,频率不再藏在材料属性里,而作为特征值显式出现。
具体操作时,可以添加“偏微分方程”接口里的“弱形式偏微分方程”,定义未知场u,然后在弱表达式里写:
test(u) · (∇×∇×u) - (ω/c)^2 · εr(ω) · u · test(u) = 0
其中εr(ω)用插值函数或者解析表达式定义。这种写法初看很劝退,但实际测试下来,它对计算频带和带隙边缘的精度很有帮助,尤其是研究石墨烯类、等离激元类色散材料时,几乎绕不开。我在复现一书中的几个金属-介质混合结构时,用的就是这个思路。标准接口算一半会报错,换弱形式后一次跑通。
3. 实操:从mph文件到自建模型的一条龙流程
3.1 5.6版本打开旧文件时先做三件事
这套mph文件虽然都是用COMSOL 5.6保存的,但在别人电脑上打开时,依然会出现各种意想不到的问题。我建议每次打开一个新文件,先做三件事,别急着点“计算”。
第一,检查“全局定义”里的参数列表。确认晶格常数a、圆柱半径r、介电常数eps_r、以及波矢参数kx、ky这些关键量是真实存在的。旧文件中参数名可能和我习惯不同,直接修改成你自己的命名规则。
第二,把“研究”节点里的“特征值搜索范围”读一遍。不同版本默认设置会有差异,5.6在特征值求解器中默认搜索频率是0到无穷,目标特征值数可能只有6个。这会导致高波段根本没参与扫描,结果里看不到高频率的带。
第三,重新构建网格再求解。mph文件里保存的网格是从原电脑生成的,一旦几何被修改或者单位设置不同,旧网格可能失效或退化。稳妥做法是删除现有网格,按原始设置重新划分,再跑一次特征值求解。这样至少能排除最简单的坑。
3.2 一维案例:多层膜能带与反射率
一维光子晶体是一维堆叠的多层膜结构,例如高折射率n1=3.4和低折射率n2=1.46交替排列。复现这类案例,我通常用一维模型就够。几何就是一段长度为a的周期单元,两端设置Floquet周期边界,材料赋值给各个层。
扫描波矢时,参数k对应传播方向的相位累积。特征值算出来的频率,直接归一化为a/λ。你会发现低频允许通过、高频附近出现带隙,带隙中心位置与关系式n1·d1 = n2·d2 = λ0/4基本吻合,这个是检验模型对不对的黄金标准。
更进阶的一维案例还要算反射谱。这时候要把模型扩展为“多层膜+两侧空气层”,外层用完美匹配层收住,入射端口用端口边界条件激发。反射率R随波长的变化会明确显示带隙位置。这个案例计算量小、逻辑清晰,适合作为整套项目的第一课。
3.3 二维案例:Floquet边界扫描不可约布里渊区
二维正方晶格是最常见的练手场景。几何设置上,晶胞边长a,中心圆柱半径r,圆柱介电常数设为ε_high,背景介质设为ε_low。圆形居中之后,对着四条边界分别设置Floquet周期边界条件,左右一对,上下另一对。
然后设置波矢扫描路径。正方晶格的不可约布里渊区路径一般是Γ→X→M→Γ,对应高对称点的坐标为:
Γ = (0, 0),X = (π/a, 0),M = (π/a, π/a)
在COMSOL里,我习惯定义一个扫描参数s,取值范围0到1,每段路径的比例长度按实际距离分配。例如Γ→X占1段,X→M占1段,M→Γ的长度会略长(√2倍),这会导致能带图横轴刻度不均匀。为了好看,需要给扫描参数设置不同的映射关系,或者在导出后用Origin/Python重新排横轴。
求解完成后,在“派生值”里提取“全局最小值”而不是“点值”,因为特征值结果通常在数据集里做的是一维极值处理。保留前8条能带,画出来就是典型的能带图。细心的话可以看到带隙出现在哪条高对称线上,场分布在带边位置的空间形态也能看得很清楚。
3.4 三维案例:网格规模控制和求解参数调整
三维光子晶体案例,最典型的是反蛋白石结构或者三维立方晶格球形孔洞。几何用三维晶胞,边长为a,内部放一个球体代表孔洞或高折射率材料。三对Floquet周期边界条件设置方式和二维完全类似,只是多了一组z方向配对。
网格是最大拦路虎。三维里如果还用三角形网格疏疏朗朗地剖,特征值误差会大得离谱。我一般给球体表面设“较细化”网格,背景区域用“较粗化”,整体自由度控制在50万以内。对于8GB内存的机器,超过这个量会开始卡顿;16GB内存则相对安全,最多可以跑到80万。
求解器方面,特征值研究建议把“线性扰动求解器”关掉,直接用默认的全耦合特征值求解器。如果内存不足,可以把“目标特征值数”从8降到4,或者缩小“特征值搜索范围”。三维案例求的不是全貌,而是关键带隙趋势,能用局部信息验证书中的结论就够了。
3.5 能带图的整理与数据导出
mph文件里面的结果图是可以直接截图的,但论文或作业里需要再加工,所以我习惯把数据导出来重绘。在COMSOL中,右键“派生值”,选择“全局计算”,在表达式栏输入实部特征频率freq,选中所有特征值模块,然后勾选“表”,最后把表格导出成csv文件。
导出文件里会有两列核心数据:扫描参数s和对应的归一化频率f·a/c0。用Python或Origin把散点画出来后,你会发现不同段路径之间的“段边界”如果没处理,横轴会出现跳跃。解决办法是手动给每段路径分配一个累计长度参数,比如x坐标,再画散点图。
这样整理出来的能带图干净清晰,和书上的图对比也方便。顺带说一句,COMSOL模型树中的“结果”节点里,我通常预先存好几个分组绘图:电场模、磁场模、能量密度,以及能带图模板。这样每次算完新案例,只需要双击运行“绘图组”,图片就自动刷新,省去了重复设置的麻烦。
4. 踩坑实录:复现过程里最常见的五个问题
4.1 特征值算出来是虚数或者负实部
这是新手最容易遇到,也最容易吓退人的问题。特征值求解器输出的是一个复数,实部是频率,虚部代表损耗或增益。正常情况下,无损耗材料的特征值,虚部应该非常小,接近零。
如果你看到实部为负、虚部很大,不用慌。先检查所有材料的介电常数是不是有虚部。有时候设置εr时误填了复数,哪怕虚部只有0.01,也会让本征频率偏移并出现明显虚部。把材料改回纯实数之后,特征值就干净多了。
还有一种情况是,当模型中有开放边界,例如空气截断面造成的泄漏模式,特征值也会变虚。能带计算里我们要求严格周期结构,这时必须确认四个或六个边界都已经配对成Floquet边界,没有哪个边条悄悄设成了默认的“完美电导体”或“连续型边界”。
4.2 能带结果和书对不上,先查单位
复现最痛苦的瞬间,是图算出来了,但纵轴数值跟书里差了十万八千里。十有八九问题出在归一化单位。书上的纵轴通常是无量纲频率a/λ,或者ωa/(2πc),这两种写法等价。而COMSOL特征值求解器返回的频率是赫兹,还需要乘上晶格常数a再除以光速c。
我来举个具体例子:假设晶格常数a=500nm,算出一个特征频率f=300THz,那么归一化频率是 f·a/c = 300e12 × 500e-9 / 3e8 = 0.5。你拿这个0.5去和书中能带图对比,才发现完全对得上。很多人直接把300THz画上去,当然和书不一样。
还有反过来的坑:如果书中设定a=1μm,而你的几何画的是a=0.5μm,所有能带频率会翻倍。所以开始建模前,先从书中判断a取了多少,再确定COMSOL几何中的单位。这个判断不花时间,但能省下一整天的排查。
4.3 边界相位设反导致能带折叠错误
Floquet边界条件的相位表达式里,正负号决定了波沿哪个方向传播。如果符号设反,计算结果会等于把k映射成了负k,而能带结构通常关于k是对称的,所以有些情况看不出区别。但在非对称结构或某些高对称点上,符号错误会让“带折叠”方向完全错误。
排查方法很直接:算一个k=0频率点,应该能观察到所有模式的场分布具有晶格相同的对称性。如果空间场分布出现明显错位,检查source边和destination边是否选择了同一组边界的两端。COMSOL的边界方向由箭头指示,需要确保source边箭头方向和destination边箭头方向一致,否则相位乘子会多出180度莫名其妙的偏差。
4.4 网格粗细与特征值搜索范围的权衡
网格加密之后,特征频率通常会降一点并趋于收敛。但真实问题是,网格粗的时候,特征值频率偏高,带宽范围和带隙边缘都是虚胖的。复现书中精确带隙边缘时,网格必须密到能分辨场在晶格内快速变化的细节。
我的经验是:先跑一个粗细的网格看趋势,例如最大单元尺寸设为a/8,能带大体轮廓先出来。然后只对带隙边界点加密到a/16,看频率变化不超过1%才敢说结果可信。二维圆柱结构可以用三角形网格,但圆柱边界的曲率会影响局部网格质量,建议在曲率较大的地方设置边界层网格。
特征值搜索范围的权衡也没有统一解。搜索范围太宽,求解时间会指数增加;太窄,会漏掉带。建议先从已知的理论带隙位置出发,把搜索范围向上扩展20%。多试几次后,你会摸到每个结构大致需要几条带才能覆盖感兴趣频率区间。
4.5 弱形式建模的细节与排查
使用弱形式方程时,最常出的错是万花筒一样的变量名不匹配。COMSOL中自定义弱形式需要显式声明测试函数变量,例如test(u)。如果表达式里写的是u,而不是test(u),软件会报“未知变量”或“变量未使用”,即使能求解,矩阵也是空的。
另外,弱形式中定义的本征值通常是一个全局参数,例如lambda或者omega。你需要在“特征值”设置里指定“本征值变量”为lambda,而且在表达式中要出现“lambda·u·test(u)”这样的质量项。如果没有质量项,特征值求解器会认为你解的是一个静态问题,输出一堆奇怪的0特征值。
排查时最好的工具是“求解器日志”,它会打印出每个归一化参数对应的自由度数和最终装配方程的数量。如果自由度数量少得离谱,多半是弱形式方程没有正确作用到域上,回去检查“启用方程”的选择框以及“域选择”是否正确。
5. 这份案例库怎么用效率最高
5.1 推荐的学习顺序和实验节奏
建议不要一次性把所有mph文件全打开,那样会看吐。合理节奏是一周一个维度:第一周一维,第二到三周二维,第四周三维。每个文件不求跑完所有能带,只取书中一个关键图进行复现,然后对照检查。
一维案例花12分钟就能完成一个完整实验。二维案例从建模到出图大约四十分钟,刚好是一个下午能专心做完两个案例的节奏。三维案例建议选重点,比如反蛋白石结构算一次第一布里渊区路径,其他相似三维结构就只改参数不深挖。这样既节省时间,又保证了整体覆盖面。
5.2 把mph文件改造成自己的研究模型
复现的终点不是把书里的图重新画一遍,而是让这些mph文件变成自己下一步研究的起点。替换几何是最容易的:把圆柱改成方柱、六边形,改变r/a比值,就能研究不同结构对带隙宽度的影响。只要参数化做得好,这个改造过程极快。
另一条路是引入缺陷。在一个二维周期结构中去掉中心某个圆柱,再扩大计算区域为3×3或5×5超胞,你会看到带隙中出现一条很平的缺陷态能级。这其实就是光子晶体波导和微腔的原型。mph文件里调整“晶格阵列”相关的几何复制次数就能实现,整个过程不需要重学新物理。
如果你对拓扑光子学感兴趣,还可以在现有能带模型中加入晶格变形参数,观测能带简并打开和边缘态的出现。来自mph文件的基础边界条件、扫描路径和特征值设置,都能原样保留,只需要修改k路径的定义和几何周期。
5.3 我的几点收尾体会
做完这40多个文件,我最深的体会是,算能带这件事本身不复杂,真正难的是结果的可信度。COMSOL里每个设置都有它存在的理由:Floquet相位不是装饰品,特征值搜索范围不是随便填的数字,网格加密不是为了打磨漂亮图。只有每一步都清楚自己为什么这么做,复现才真正起到作用。
如果非要说一个小技巧,就是反复使用“对照实验”的方法:故意改错一个参数,比如把边界相位符号取反,看看能带会发生什么变化。看一眼错误结果再改成正确设置,比直接得到正确答案更能加深理解。这套mph文件现在不仅是我自己的学习笔记,也是一份可以分享给后来者的数字资源,希望它能帮更多人在光子晶体的路上少掉一点头发。