做二维光子晶体谷霍尔效应仿真这件事我在COMSOL里折腾了整整一周才把第一张像样的能带图跑出来。最难受的不是物理概念不懂而是软件里一堆隐形的“坑”特征值解出来全是负数、Floquet周期边界的波矢方向定义反了、K点简并死活不打开、超胞里边界态找不到……如果你也在复现文献里的谷霍尔光子晶体这篇就把我从建模到边界态计算的全流程、参数设置的出发点、以及踩坑后总结的排查思路一次讲清楚。这篇文章面向的是正在用COMSOL做二维光子晶体能带计算和边界态模拟的研究生或工程师。你不需要已经有拓扑光子学基础但至少要会COMSOL的基础几何操作和“特征值”研究步。我会把能带绘制和边界态探索这两件事拆成可操作的技术路径并且解释每一步背后的物理逻辑。1. 谷霍尔效应在光子晶体里到底是什么先讲原理再谈仿真1.1 从谷电子学到谷光子晶体K和K谷是怎么来的谷霍尔效应这个概念最早来自电子体系。在石墨烯这类六角晶格材料里能带在第一布里渊区角落存在两个不等价的能量极值点习惯上分别叫K谷和K谷。电子在这两个谷里拥有相反的角动量类量子数这就是谷自由度。后来人们发现如果把电子体系里的谷物理搬到光子晶体里同样可以实现拓扑边界态于是有了谷光子晶体。在光子晶体中实现谷自由度的前提是能带在K点存在简并。比较经典的做法是用三角晶格或六角晶格的光子晶体。在二维情况下TE极化的能带在布里渊区角落往往会出现双重简并形成类似电子体系里的狄拉克锥。这个简并就是谷简并的雏形。不过光子和电子有一点本质区别电子有自旋光子没有。所以要在光子晶体中实现“谷锁定”的拓扑边界态不能靠打破时间反演对称性而是要靠打破空间对称性。最常见的手段是使系统失去镜面对称让原本在K点简并的两个模式劈裂打开带隙。这样形成的带隙被称为谷带隙带隙两侧能带的谷陈数相反在两个不同拓扑性质的区域交界处就会产生只能沿一个方向传播的谷锁定边界态。1.2 解开简并的老办法旋转三角形孔打破C3v对称实现谷带隙的结构有很多最直观、最适合COMSOL初学的还是“三角晶格中放置三角形空气孔”的方案。选择这个结构有几个理由三角形孔自身有C3v对称性旋转角度可以作为连续的拓扑相调节旋钮当旋转角为0°或60°等特殊角度时整个晶格保持镜面对称K点简并存在当旋转角偏离这些特殊角度系统的镜面对称被破坏K点简并劈裂带隙开始出现旋转角取正或负得到的能带拓扑性质相反这正是构造边界态的基础。用COMSOL来做这件事最大的优势是几何不用像MPB那样靠脚本写一堆网格而是直接在GUI里画出来并参数化本征模的电场分布、能流密度都可以直接可视化。这对理解“谷选择规则”和“边界态局域”非常有帮助。1.3 为什么我在COMSOL里做而不去用MPB或Python见仁见智但我的体会是MPB一类平面波展开工具算能带确实快但建几何特别痛苦尤其到了超胞边界态计算稍复杂的界面结构就要写很长的Python脚本。COMSOL的优势在于几何操作所见即所得参数化扫描可以无脑点开Floquet周期边界条件内置本征值问题直接求解模态场的后处理极其友好边界态长什么样一眼就能看到多物理场扩展方便后续想加非线性、热效应、应力都不用换软件。缺点是每算一次本征值都要重新扫参数速度远不如平面波展开而且COMSOL的特征值符号和频率换算逻辑跟一般教材不完全一致这是新手最容易懵的地方。后面我会专门用一节来讲。2. 菱形晶胞与三角形空气孔几何建模的参数化思路2.1 单胞、晶格基矢和高对称点的位置关系先把坐标系和记号定下来。下面的三角晶格基矢取为a1 (a, 0)a2 (a/2, √3 a/2)其中a是晶格常数我这里取a 1 μm方便后面把所有频率换算成归一化频率a/λ。在这个晶格里第一布里渊区的高对称点在COMSOL中最常用的笛卡尔坐标写法是高对称点kxkyΓ00K4π/(3a)0M02π/(√3 a)我这里把M点放在ky轴上路径取Γ→K→M→Γ。需要提醒的是高对称点坐标的写法在不同文献里可能不同因为倒格子坐标变换和晶格旋转会改变k的表示。只要你用的正空间基矢和我给出的定义一致这组坐标不会有问题如果你们习惯的M点坐标不同其实是同一个物理点的不同等效表示能带结果不会改变。单胞几何用菱形。菱形的四个顶点分别为P1 (0, 0)P2 (a, 0)P3 (1.5a, √3a/2)P4 (0.5a, √3a/2)这个菱形正好对应上面的两个基矢平移是三角晶格的最小平行四边形单胞。在COMSOL 2D组件里用“多边形”工具依次连接这四个顶点生成域即可。2.2 COMSOL几何操作的完整序列附参数表打开COMSOL新建一个2D组件在“全局定义”里先建好参数表。我建议所有几何参数都用全局参数控制而不是直接填数字这样后面扫描会非常方便。我的初始参数表如下参数表达式说明a1[um]晶格常数n_s3.45基板折射率硅l_tri0.4*a三角形孔边长theta15[deg]三角形旋转角r_fillet0.02*a三角形顶点圆角半径几何步骤按顺序做用“多边形”工具画三角形孔。为了让旋转角theta能直接控制我先把三角形中心放在原点附近再转到正确位置。三角形三个顶点可以用参数化坐标表示。边长为l_tri的正三角形中心在原点时顶点坐标取(l_tri/√3, 0)、(-l_tri/(2√3), l_tri/2)、(-l_tri/(2√3), -l_tri/2)旋转平移后放到晶胞中心(0.5a, √3a/4)。在“几何”里添加“旋转”节点对三角形施加角度theta的旋转中心选三角形的重心。用“多边形”画菱形域四个顶点坐标按上面的P1~P4填入。用“布尔差集”将菱形域减去三角形孔。这样我们就得到了一个介质背景、带一个空气三角形孔的晶胞。对三角形的三个尖角做圆角处理。这一步非常重要我在下一小节单独说。需要说明的是三角形的初始朝向会影响对称性破缺的方向。你只要保证theta0时三角形的一条对称轴与晶格的高对称方向重合比如三角形的一个顶点指向x轴正方向或负方向那theta扫描的结果是一样的。如果theta0时简并没出现先检查朝向。2.3 圆角处理尖角对网格质量和特征值收敛的影响我最初跑不出稳定的能带图很大原因是没有做圆角。三角形空气孔三个尖角处电场会有奇异性直角甚至锐角会导致本征值求解器在那里反复迭代不收敛特征值列表里出现大量莫名其妙的数值。处理方式是在每个顶点加一个小圆角半径大概0.02a左右。加了圆角后高频模的收敛性会明显改善。圆角半径不要太大不然结构的对称性虽然没变但实际打开的带隙宽度和文献里对不上。如果你在复现具体论文圆角半径最好跟文献一致如果只是自己研究趋势r_fillet0.02a是个很稳的默认值。圆角的做法很简单在COMSOL几何序列中选中三角形孔边界使用“圆角”节点指定三个顶点和半径。注意圆角后的边界一定要重新参与布尔差集操作顺序不能乱否则差集结果会和预期不符。网格方面我用物理场控制网格单元大小选“较细化”再在空气孔附近加一个“网格细化”域最大单元尺寸设为0.05a。这样既能保证计算精度又不会让自由度过大导致本征求解很慢。我算一个单胞能带大概只需要几万个自由度几秒钟就能得到一组k点的特征值。3. Floquet周期边界与能带扫描从负特征值到归一化频率3.1 特征值求解的物理方程与COMSOL特征值含义能带计算的本质是在周期性边界条件下求解电磁场的本征模式。COMSOL“电磁波频域”接口在二维模型里用的是不含源的亥姆霍兹方程[ abla \times \mu_r^{-1} abla \times \mathbf{E} - k_0^2 \varepsilon_r \mathbf{E} 0 ]这里k0是真空中的波数。当使用“特征值”研究时COMSOL把k0²当作特征值来求解。它输出的特征值是一个负数记作λ那么实际频率f和λ的关系是[ f \frac{c}{2\pi} \sqrt{-\lambda} ]注意这里c是真空光速。很多人第一次看到一堆负特征值以为算错了其实完全正常。这个符号问题在COMSOL官方文档里有但经常被教程忽略我在这里帮你踩掉这个坑。实际操作里如果你想直接得到归一化频率a/λ可以在结果后处理时增加一个表达式比如sqrt(-lambda)/(2pic)*a然后绘图时直接画这个表达式。我一般习惯把a以米为单位、c以m/s为单位算出来的归一化频率就是无量纲数。3.2 设置Floquet周期边界和k路径参数物理场选“电磁波频域”极化方式选择TE面外电场也就是E沿z方向这个选择对应大多数谷光子晶体文献里的TE模式。如果你要算TM把物理场设置改为面外磁场即可流程一模一样。周期性边界条件用“Floquet周期性”。在这个节点里需要指定周期方向和Bloch波矢k。对菱形单胞两个周期方向正好对应平移基矢a1和a2。在COMSOL里你需要分别识别两组平行边一组是P1-P2和P4-P3边另一组是P1-P4和P2-P3边。给两组边都加上Floquet周期条件并指定Bloch波矢写为k_Floquet (kx, ky)其中kx、ky就是我们要扫描的参数。接下来的问题是路径。根据前面表格里的高对称点坐标我们需要的k扫描路径是Γ到Kkx从0变到4π/(3a)ky保持0K到Mkx从4π/(3a)线性降到0ky从0线性升到2π/(√3a)M到Γkx保持0ky从2π/(√3a)降到0。在COMSOL里实现这一段扫描我的做法是在“研究1”下面添加了一个“参数扫描”把(kx, ky)作为一个参数表逐行扫描。这个参数表可以直接手工填写比如每个路径段取6到10个点数量不用太多能带趋势已经足够清楚。这里有个操作细节参数扫描支持“参数表达式列表”你也可以把路径写成语义变量再加条件表达式实现但我觉得最直观的还是直接列表。尤其在COMSOL 6.x版本里参数扫描列表可以直接粘贴表格数据非常方便。3.3 求解配置、后处理以及能带上那些“讨厌的伪模”在“特征值”研究步设置里搜索目标频率范围要设置成你关心的归一化频率附近。例如我关心的频率范围在0.2~0.6(c/a)就在“特征值搜索”里把基准设为这个范围的中心并要求求解器返回6到8个特征值。太少会漏带隙附近模式太多会增加求解时间。求解完成后后处理流程是在“派生值”里添加“全局计算”计算sqrt(-lambda)/(2pic)把这个值当作纵轴把扫描索引当作横轴绘图用“一维绘图组”里的点图把所有特征值绘制出来每个特征值就是一个频率点。绘制出来后你能看到一组沿着k路径变化的离散频率点。把它们连起来就是能带。但这里会出现一个麻烦COMSOL默认的特征值排序是按实部大小或求解器内部排序来的在跨越简并点或者带隙边缘时不同k点间同一条能带的点会“跳”画出来像乱码。我的经验是不要依赖COMSOL自动排序直接用点图而不连线肉眼就能看出能带分支想连线的话导出数据后在Excel或Python里按频率大小和路径顺序做二次排序。物理上我们其实知道第n条能带在整个路径里是连续的只是数值解排序不连续看清楚趋势即可。伪模的问题也值得一提。当网格太粗或特征值搜索范围过大时结果里会出现一些在物理上不存在的模式典型特征是场分布呈棋盘状或强烈集中在个别网格点上。判断方法就是看电场模分布。如果某个模式对应频率落在带隙中但场没有沿着周期结构传播而是一堆孤立的峰值那基本可以断定是数值伪模。遇到这种情况先加密网格再缩小特征值搜索范围伪模一般会消失。当你把旋转角theta设成0°时K点处应该出现双重简并也就是两条能带在K点相交。如果扫描精度足够你会看到两簇点重合在同一个频率上。当我第一次在COMSOL里看到这个简并点才知道前面的几何和边界条件设置都对了。接下来把theta加到15°K点处的简并劈裂成上下两条能带之间出现一个带隙这正是谷带隙。4. 从能带到边界态超胞拼接、周期边界和色散线识别4.1 正负旋转角拼接如何构造两边“拓扑相不同”的界面能带里打开了谷带隙只是第一步边界态才是谷霍尔效应的核心体现。要产生边界态我们需要两个区域分别处于相反的拓扑相然后把它们拼接起来。在三角形孔旋转方案里最简单的做法是让界面两侧三角形孔的旋转角一正一负比如左侧theta15°右侧theta-15°其他参数完全一致。为什么正负角度对应相反拓扑相因为旋转角的正负改变的是系统镜面对称破缺的方向这会让K谷和K谷的带隙符号发生翻转等效于谷陈数变号。在界面处两个区域的谷陈数跃变根据体边对应原理带隙内必然出现边界态。构造超胞时我在COMSOL里新建了一个组件把之前的单胞几何复制进来然后用“阵列”节点沿x方向排了四列单胞theta设为15°再排四列theta设为-15°中间形成一个竖直界面。界面放在两列晶胞之间而不是穿过空气孔这样界面处的拼接才是自然连续的也更接近文献里的zigzag型边界。超胞沿y方向只取一个晶胞宽度即可因为边界态沿界面平移不变一个周期就够了沿x方向两侧各取4个晶胞是为了让边界态的场在超胞边界处已经衰减到可以忽略避免因有限尺寸带来的边界反射影响结果。4.2 超胞算边界态时的边界条件选型超胞计算里y方向和单胞能带一样采用Floquet周期边界条件Bloch波矢取ky即沿界面方向。我们需要扫描ky画出色散关系。x方向则不能再周期化因为超胞在x方向本来就不是平移对称的两侧要设置开放边界。在COMSOL里最直接的办法是加“散射边界条件”。虽然散射边界对平面波有一定反射但对于本征值问题我们主要是想看带隙中是否存在局域在界面的模式散射边界的微小反射影响不大。若想做得更严谨可以在模型两侧再各加一层厚度约一个晶格常数的均匀介质层并把最外侧设为“阻抗边界条件”效果会稍微好一些。也有人用PML来做但PML在本征值问题中会引入复特征值而且物理上那些真正局域的边界态频率在复平面里的分布容易和其他泄漏模混在一起新手不好区分。我自己在初学阶段用PML栽过跟头后来换成散射边界条件反而更加干净。所以如果你只是复现边界态色散线散射边界条件完全够用。特征值扫描的设置和单胞能带类似但搜索范围要缩小到谷带隙附近。比如单胞能带算出来的谷带隙在0.3~0.38(c/a)区间那超胞特征值搜索基准就设为0.34(c/a)返回6~10个特征值。扫描ky从-π/a到π/a步长取0.05π/a左右大约几十个点算完绘制频率对ky的色散图。4.3 怎么确认你在带隙里找到的不是表面态或普通体态色散图画出来后你会在体态连续谱的带隙区域看到一两条孤立的色散曲线斜率和两侧的体态都不一样横跨整个谷带隙。恭喜这大概率就是边界态。但仅凭色散线上看还不够必须看模式场分布。在结果里选中边界态对应的特征值节点绘制电场模。判断标准有三个场强峰值明显集中于两种晶胞交界的竖直界面附近离开界面往左右衰减沿界面方向的场分布具有周期性和连续性而不是一团散乱在不同ky点比如ky0和kyπ/a看向界面两侧的场分布能看到能量偏向界面不同侧或不同谷的特征这正是谷锁定行为的体现。如果你发现的色散线确实穿过带隙但场分布是基本铺满整个超胞的那它多半是数值伪模或体态投影。COMSOL里还有一种比较坑的情况多量子阱式的界面两侧各自存在表面态场局域在超胞的左或右外边界而不是在中间界面。这是因为超胞外边界虽然不是周期边界但散射边界条件并不能完全消除表面局域模。遇到这种情况把超胞两侧再多加两列晶胞边界态就会明显集中于界面。还有一点边界态的色散曲线在ky0处通常会有一个极小值点或交叉点。不同结构和界面对应细节不同但只要曲线位于带隙内且边界两侧拓扑性质相反理论上必有一条边界态色散线穿过带隙。你不需要额外编程去算拓扑不变量能带劈裂和边界态存在本身就是很好的验证。5. 参数扫描与带隙优化让边界态更“好用”5.1 旋转角θ对带隙宽度的影响规律算出了边界态接下来自然想找一组参数让带隙更大、边界态色散更陡、工作频率更合适。旋转角theta是最直接的控制参数。在COMSOL里做这个扫描非常简单把之前单胞能带研究的参数扫描改为扫描theta变量范围从0°到60°每个角度都计算K点附近的前几个特征值。注意由于对称性theta和60°-theta的结果往往是对称的实际只需要扫0°到30°就能看到完整趋势。我扫下来的典型结果是theta从0°开始增大时谷带隙宽度先增后减在某个中间角度取得最大值继续增大到60°附近带隙又重新闭合。带隙最大对应的角度和三角形边长l_tri有关。比如l_tri0.4a时最佳角度大约在15°到25°之间。需要提醒的是旋转角太大时三角形孔之间容易靠得太近甚至重叠。你在建模时要做个“几何相交”检查确保空气孔之间有足够介质间隔。COMSOL几何构建时如果出现自相交求解器会在网格划分阶段报错这是一个明显的提示。5.2 三角形边长、晶格常数与背景介电常数的协同影响除了旋转角三角形边长l_tri对带隙位置和宽度的影响也非常明显。l_tri太小空气占比低带隙变窄l_tri太大孔间介质太薄同样不利于带隙。实际调优时我会固定theta扫描l_tri从0.3a到0.5a每个值算一次能带比较带隙大小。背景介电常数的影响也有规律折射率增大整体频带往低频方向移动各能带之间的相对劈裂比例变化不大。如果你希望把工作频率调到特定波段比如近红外或通信波段最直觉的做法是修改晶格常数a因为归一化频率a/λ不变时实际频率随a线性变化。比如在近红外工作可以设a450nm然后用硅n3.45边界态就会落在约1550nm附近。网格收敛性也必须在调参时一起检查。我习惯用一个固定网格和一个加密一倍网格分别算一遍关键角度下的带隙宽度如果差异小于1%就可以认为当前网格足够可靠。这个检查虽然费点时间但能避免后续花大量时间在错误的“优化结果”上。5.3 扫描结果导出与绘制一张清晰的Δ-θ曲线怎么来想画带隙宽度随角度变化的曲线关键是要自动提取每条能带在带隙附近的极值频率。我的做法是在COMSOL里固定k点为K点计算前6个特征值用“派生值”里的“全局评估”把每个特征值对应的频率算出来在参数扫描结果中把每个theta下的特征频率导出成表格在Python或Excel里对应到能带分支计算第n条能带的最大频率和第n1条能带的最小频率差。第3步导出的数据在能带简并点附近排序会跳这是正常现象。我通常只看K点附近的带隙因为谷带隙在K点的频差就足以表征拓扑带隙宽度。你不需要整条能带都追踪。另外在优化边界态工作时除了关注带隙宽度还要看边界态色散线的斜率。斜率越大边界态的群速度越大能量输运越快。调参时可以顺手在超胞色散图的边界态线附近算一下dω/dk用来衡量边界态“好不好用”。最后再分享一个小技巧COMSOL参数扫描完成后所有结果会存在“求解器日志”里。如果你需要批量处理数据可以在结果节点添加“表格”然后把“全局评估”的输出自动追加到表格里。导出的CSV文件可以直接用matplotlib画图。这样固定theta扫l_tri、固定l_tri扫theta都不会把自己困在重复手动导数据里。我现在的习惯是先在单胞里跑一组粗略扫描确定可用的theta和l_tri区间再在这个区间里加密采样最后拿最优参数去超胞里确认边界态色散和场局域。整个过程在COMSOL里一套走下来半天时间能出完整的结果。比起一开始就在超胞上盲目试参数这样分步走的效率高得多。
