在计算投影能带图的时候,一个重要的问题就是能带太多了,每个K点都有一大堆能带,如果想要画出某个频率区间内波导态的场图,必须确定这个波导态在对应K点的序号,这个序号可以用这个脚本查阅:
# ================= 找到特定k下,波导态所在的BAND序号 =================
# 1. 选一个 k 点索引(比如 Γ 是 0,Y 是 len(k_points)-1)
k_index =4 # 例如 Y 点,可改成你要看的点
# 2. 设定你感兴趣的频率窗口
f_min, f_max = 0.3, 0.4 # 根据你的能带图调整
# 3. 在该 k 点找出落在这个窗口内的 band
target_bands = []
for band in range(tm_freqs.shape[1]):
f = tm_freqs[k_index, band]
if f_min <= f <= f_max:
target_bands.append(band)
print(f"在 k 点索引 {k_index},频率窗口 [{f_min}, {f_max}] 内找到 band: {target_bands}")
比方说,结果显示找到能带14.
具体的频率范围由我们肉眼通过观察法确定。
但是这个方法有个陷坑,就是后面画场图分布的时候,比如:
band_1based = 15
XXXX
field = ms.get_efield(band_1based, bloch_phase=True)
Ez = field[..., 0, 2]
这个波导态的序号需要加一。
原因(AI说):
具体发生了什么
你的查找代码用的是 numpy 下标(0 起)
range(tm_freqs.shape[1])生成的band是0, 1, 2, ...,所以target_bands = [14]里的 14 是numpy 数组的列索引,对应tm_freqs[:, 14]这条能带。
output_at_kpoint回调里的band是 1 起
MPB 底层是 C/Fortran 写的,能带编号从1开始。Python 封装在回调里把 C 的编号直接传了进来,所以这个band是1-indexed。
回调里
band = 1↔ numpy 数组的tm_freqs[:, 0]回调里
band = 15↔ numpy 数组的tm_freqs[:, 14]
你设band_index = 14,在回调里匹配到的其实是 numpy 数组的tm_freqs[:, 13],也就是相邻的另一条能带,所以场图不对。改成band_index = 15就对了。
为什么get_efield(band)本身没问题
ms.get_efield(band)用的也是同一个 1-indexed 编号,所以只要你在回调里匹配对了,传给get_efield的band就是正确的。问题只出在你用来比较的那个band_index是从 0 起的数组下标,两边编号体系不一致。
如果你在画场图的时候指定画序号0波导态能带的场图,那么程序会立即报错,因为画场图的时候不存在序号0的能带,能带是从1开始数的。
但是最上头的那个脚本,能带是从0开始数的,这一点是个重要的容易忽略的坑。