본문으로 건너뛰기

10. Eigenchannel 분석

7장에서 얻은 transmission T(E)T(E)는 에너지별 총 투과율일 뿐, 전자가 접합의 어디를 통해 흐르고 어디서 반사되는지는 말해주지 않는다. 이 장에서는 총 transmission을 서로 독립인 전도 채널(eigenchannel)로 분해하고, 각 채널의 산란 파동함수를 실공간 cube로 렌더링해 전류 경로를 직접 눈으로 확인한다. 핵심은 이것이 재계산이 아니라 후처리라는 점이다 — 6장에서 이미 저장한 trans.TSHS와 전극 Electrode.TSHS만 있으면 된다.

학습 목표

  • transmission을 채널별 고유값 τi\tau_i로 분해하는 이론적 근거를 이해한다.
  • sisl 후처리로 Green 함수 → spectral function → eigenchannel을 구성한다.
  • 채널 파동함수를 Re / Im / ψ2|\psi|^2 cube 3종으로 저장하고 VESTA로 시각화한다.
  • eigenchannel을 뽑을 에너지를 고르는 기준과, 잘못 골랐을 때의 자가 검증법을 익힌다.

이론: 총 투과를 독립 채널로 분해한다

NEGF에서 transmission은

T(E)=Tr ⁣[ΓLGrΓRGa]T(E) = \mathrm{Tr}\!\left[\Gamma_L\, G^r\, \Gamma_R\, G^a\right]

로 주어진다 (4장). 이 trace는 Hermitian 행렬 ttt^\dagger t (tΓR1/2GrΓL1/2t \equiv \Gamma_R^{1/2} G^r \Gamma_L^{1/2})의 trace로 다시 쓸 수 있으므로 적절한 유니터리 회전으로 대각화할 수 있고, 그 고유 기저가 바로 eigenchannel이다:

T(E)=iτi(E),0τi1.T(E) = \sum_i \tau_i(E), \qquad 0 \le \tau_i \le 1 .

τi\tau_i는 "ii번째 채널이 열려 있는 정도"이며, 채널 하나가 완전히 열리면(τi=1\tau_i = 1) 정확히 전도 양자 G0=2e2/hG_0 = 2e^2/h 하나를 나른다. 채널 분해는 단순한 수학적 재표현이 아니라 물리적 정보를 담는다:

  • 채널 수 counting — ballistic 1D 도체의 T(E)T(E) 정수 plateau는 열린 채널 수와 같다. 균일 cumulene chain은 EFE_F 근처에 축퇴된 πx\pi_x, πy\pi_y 두 밴드가 있으므로 T(EF)2T(E_F) \approx 2, 즉 τ0τ11\tau_0 \approx \tau_1 \approx 1이 기대된다.
  • 산란의 국소화 — 불순물이 있으면 특정 채널의 τ\tau만 억제되고, 그 채널의 ψ2|\psi|^2가 불순물 자리에서 꺾이는 모습으로 "어디서 반사되는가"를 보여준다.
  • shot noise — Fano factor가 iτi(1τi)/iτi\sum_i \tau_i(1-\tau_i) / \sum_i \tau_i로 결정되므로, 같은 TT라도 채널 구성에 따라 잡음이 다르다.

구성 절차는 Paulsson–Brandbyge 방법을 따른다. 좌측 전극에서 주입된 모든 산란 상태를 담는 좌측 spectral function

AL(E)=GrΓLGaA_L(E) = G^r\, \Gamma_L\, G^a

를 대각화해 주입 상태 기저를 얻고, 이를 ΓR\Gamma_R로 회전하면 고유값이 τi\tau_i, 고유벡터가 채널 파동함수가 된다. SIESTA의 PAO 기저는 비직교이므로 overlap SS의 Löwdin 직교화(S1/2S^{1/2}를 양쪽에 끼우는 변환)가 반드시 선행되어야 한다.

방법: 재계산이 아니라 sisl 후처리다

필요한 입력은 세 가지다.

파일출처역할
trans.TSHS6장 device 0 V 계산디바이스 Hamiltonian + overlap
Electrode.TSHS5장 전극 계산반무한 전극 self-energy 생성
*.ion.xmlSIESTA 계산 디렉토리basis orbital의 radial 정보 (cube 생성용)

TBtrans에는 채널 고유값을 텍스트로 출력하는 TBT.T.Eig 옵션이 있지만 사용하지 않는다. 출력 nc 파일이 수 GB로 커지고 메모리 부족(OOM)의 원인이 되는 데다, 파동함수는 어차피 주지 않는다. 채널 고유값과 파동함수 모두 위의 후처리로 얻는 것이 표준이다.

노트

cube 생성에는 각 orbital의 radial 함수가 필요하며, sisl은 이를 *.ion.xml에서 읽는다. plain *.ion 파일은 sisl이 지원하지 않으므로 SIESTA 계산 디렉토리에서 *.ion.xml을 지우지 말고 함께 보관한다. 또한 Hamiltonian은 TSHS를 직접 읽기보다 input.fdf 경유로 읽는 것이 안전하다 — fdf sile이 같은 디렉토리의 *.ion.xml을 찾아 geometry에 basis 정보를 실어 주기 때문이다.

에너지 선택 — 분석 질문에 맞는 에너지

eigenchannel은 어느 에너지에서나 정의된다. 불순물/분자 접합에서는 보통 EFE_F 부근의 공명 또는 transmission dip을 선택해 수송에 직접 관련된 산란 상태를 분석한다. PDOS의 가장 큰 peak가 항상 적절한 선택은 아니므로, 선택한 에너지와 분석 목적을 함께 제시해야 한다.

뽑은 뒤 반드시 자가 검증한다:

  • 국소 공명이면 한 채널이 지배할 수 있다 — τ0\tau_0TT의 대부분을 차지하는지 확인한다.
  • 여러 채널의 기여T>1T>1은 다중 모드 전극에서 물리적으로 정상일 수 있다. 오류 판정 기준이 아니라, 선택한 에너지에서의 밴드·PDOS·채널 대칭성과 함께 해석한다.
  • T0T \approx 0(사실상 단절)인 에너지에서는 전달 채널 자체가 없다. 이때는 τi\tau_i 고유벡터 대신 좌측 주입 scattering state(ALA_L의 고유상태)를 렌더해 "여기서 막힌다"를 시각화한다.

코드

아래 스크립트는 저장소 code/ch10-eigenchannel/eigenchannel.py에 있다. sisl은 버전에 따라 API가 조금씩 다르므로(0.14+ 기준), 함수 시그니처가 맞지 않으면 sisl 공식 문서를 확인한다.

code/ch10-eigenchannel/eigenchannel.py
import numpy as np
import scipy.linalg as sla
import sisl
from sisl.physics.electron import wavefunction

# ---------------------------- 사용자 설정 ----------------------------
FDF = "input.fdf" # 디바이스 계산 입력 (geometry + basis 로딩용)
ELEC_TSHS = "../electrode/Electrode.TSHS"
ENERGIES = { # eV, E - E_F 기준
"EF": 0.0,
"dip": -0.85, # 7장 T(E)에서 직접 읽은 dip 에너지로 교체할 것
}
ETA = 1e-3 # eV. Green 함수 허수부
NA_ELEC = 4 # 디바이스 양끝에서 전극 1 cell에 해당하는 원자 수 (C4)
NCHAN = 2 # cube로 저장할 채널 수
GRID_SPACING = 0.2 # Ang
# ---------------------------------------------------------------------

# 1) Hamiltonian 읽기 — fdf 경유로 읽으면 *.ion.xml basis가 geometry에 실린다
H = sisl.get_sile(FDF).read_hamiltonian() # SystemLabel(trans)의 TSHS를 자동 탐색
H_el = sisl.get_sile(ELEC_TSHS).read_hamiltonian()

geom = H.geometry
no = H.no

# 2) Gamma-point 밀집 행렬 (1D chain: transverse k 평균 불필요)
Hd = H.Hk(format="array")
Sd = H.Sk(format="array")

# 3) 반무한 전극 self-energy — transport 축 z: 좌측 -C, 우측 +C
SE_L = sisl.physics.RecursiveSI(H_el, "-C")
SE_R = sisl.physics.RecursiveSI(H_el, "+C")

idx_L = geom.a2o(np.arange(NA_ELEC), all=True)
idx_R = geom.a2o(np.arange(geom.na - NA_ELEC, geom.na), all=True)

def broadening(sig):
return 1j * (sig - sig.conj().T)

for label, E in ENERGIES.items():
Z = E + 1j * ETA

# self_energy의 에너지 인자 규약(복소 E vs eta 키워드)은 sisl 문서 확인
seL = SE_L.self_energy(Z)
seR = SE_R.self_energy(Z)

SigL = np.zeros((no, no), dtype=complex)
SigR = np.zeros((no, no), dtype=complex)
SigL[np.ix_(idx_L, idx_L)] = seL
SigR[np.ix_(idx_R, idx_R)] = seR

GamL = broadening(SigL)
GamR = broadening(SigR)

# 4) Green 함수와 좌측 spectral function
G = np.linalg.inv(Z * Sd - Hd - SigL - SigR)
A_L = G @ GamL @ G.conj().T
T_ref = np.trace(GamR @ A_L).real # 총 transmission (대조용)

# 5) Loewdin 직교화 후 A_L 대각화 (Paulsson-Brandbyge)
S12 = sla.sqrtm(Sd).real
S12i = np.linalg.inv(S12)
A_bar = S12 @ A_L @ S12
GamR_bar = S12i @ GamR @ S12i

lam, U = np.linalg.eigh(A_bar)
lam = lam.clip(min=0.0)

# 주입 상태를 스케일한 뒤 Gamma_R로 회전 -> tau_i
Ut = U * np.sqrt(lam / (2.0 * np.pi))
M = 2.0 * np.pi * (Ut.conj().T @ GamR_bar @ Ut)
tau, W = np.linalg.eigh(M)
order = np.argsort(tau)[::-1]
tau, W = tau[order], W[:, order]

print(f"[{label}] E-E_F = {E:+.3f} eV T = {T_ref:.4f} "
f"sum(tau) = {tau.sum():.4f}")
print(" tau_i =", np.round(tau[:6], 4))

# 6) 채널 파동함수의 PAO 계수 (비직교 기저로 환원)
psi = S12i @ (Ut @ W)

# 7) 실공간 cube 3종 (Re / Im / |psi|^2)
for i in range(NCHAN):
c = psi[:, i]
grid = sisl.Grid(GRID_SPACING, geometry=geom, dtype=np.complex128)
wavefunction(c, grid, geometry=geom) # *.ion.xml 필요

for kind, data in (("Re", grid.grid.real),
("Im", grid.grid.imag),
("psi2", np.abs(grid.grid) ** 2)):
out = sisl.Grid(GRID_SPACING, geometry=geom, dtype=np.float64)
out.grid[:] = data
out.write(f"EC_{i}_{kind}_{label}.cube")

스크립트가 하는 일을 요약하면: TSHS 두 개를 읽고, 전극 Hamiltonian의 반무한 반복(RecursiveSI)으로 self-energy를 만들고, 디바이스 양끝 orbital 블록에 심은 뒤, Green 함수와 ALA_L을 밀집 행렬로 직접 구성한다. 1D chain은 행렬 크기가 작아(orbital 수백 개) 노트북에서도 즉시 돈다. 검증 포인트는 두 가지가 내장되어 있다 — sum(tau)가 trace 공식의 T와 일치해야 하고, 격자 위에서 ψ2=Re2+Im2|\psi|^2 = \mathrm{Re}^2 + \mathrm{Im}^2이 성립해야 한다.

실행

cd device_0bias # trans.TSHS, input.fdf, *.ion.xml이 있는 디렉토리
python eigenchannel.py

출력 예시(수치는 basis·pseudopotential에 따라 달라진다):

stdout (예시)
[EF] E-E_F = +0.000 eV T = 1.5321 sum(tau) = 1.5321
tau_i = [0.9812 0.5509 0. 0. 0. 0. ]
[dip] E-E_F = -0.850 eV T = 0.3130 sum(tau) = 0.3130
tau_i = [0.2954 0.0176 0. 0. 0. 0. ]

에너지당 채널 2개 × cube 3종 = 6개의 cube 파일이 생긴다: EC_0_Re_EF.cube, EC_0_Im_EF.cube, EC_0_psi2_EF.cube, ... (파일명 규칙: EC_채널번호_종류_에너지라벨.cube).

분석: cube를 읽는 법

VESTA에서 EC_0_psi2_EF.cube를 열고 isosurface level을 최대값의 수 퍼센트 수준으로 낮추면 채널의 공간 분포가 보인다. 세 종류를 함께 봐야 하는 이유가 있다:

  • ψ2|\psi|^2 — 전류가 지나는 경로. 진폭이 어디서 급감하는지가 반사 지점이다.
  • Re, Im — scattering state는 복소 진행파다. 진행파는 Re와 Im이 4분의 1 파장 어긋난 쌍으로 나타나고, 반사가 강해 정상파가 되면 마디(node)가 공간에 고정된다. Re/Im 없이 ψ2|\psi|^2만 보면 진행/정지를 구분할 수 없다.

C19N 예제에서 기대되는 그림은 다음과 같다. EFE_F에서는 두 π\pi 채널 중 하나가 N 자리를 비교적 잘 통과하고, dip 에너지에서는 주입 측(왼쪽)에 정상파 무늬가 서고 N 자리를 지나며 진폭이 급감한다 — N 불순물에서의 반사가 실공간에서 직접 보이는 것이다. 균일한 C20 chain(연습문제 1)과 비교하면 차이가 명확하다.

연습문제

  1. N을 C로 되돌린 pristine C20 device에서 같은 스크립트를 돌려 보라. EFE_F 근처에서 τ0τ11\tau_0 \approx \tau_1 \approx 1의 두 채널이 나오는지, cube가 chain 전체에 균일하게 퍼지는지 확인하라.
  2. C19N의 불순물 PDOS(7장의 PDOS 추출)에서 EFE_F 최근접 peak와 가장 큰 peak를 각각 찾아, 두 에너지에서 eigenchannel을 뽑고 채널 수와 τi\sum\tau_i로 어느 쪽이 국소 공명인지 판별하라.
  3. ETA10310^{-3}에서 10210^{-2} eV로 올리면 τ0\tau_0와 cube 모양이 어떻게 바뀌는가. η broadening artifact를 읽고 결과를 해석하라.

참고문헌

  • M. Paulsson and M. Brandbyge, "Transmission eigenchannels from nonequilibrium Green's functions", Phys. Rev. B 76, 115117 (2007). DOI 10.1103/PhysRevB.76.115117
  • sisl 공식 문서: https://zerothi.github.io/sisl/