Qsymm 和 kdotp_symmetry 对比

Qsymm 和 kdotp_symmetry 是目前比较成熟的两个自动化生成 kp 哈密顿量的 python 库,本文主要是通过实例来对比于这两个库。

Qsymm 文档: Generating \(k \cdot p\) models — Qsymm 1.4.0-dev10+gc8e0f55.dirty documentation

Kdotp_symmetry 文档:kdotp-symmetry — kdotp-symmetry 1.0.1 documentation (greschd.ch)

例子1: Hexagonal warping

这是三维拓扑绝缘体的表面哈密顿量模型。

import numpy as np
import sympy
import qsymm

# C3 rotational symmetry - invariant under 2pi/3
C3 = qsymm.rotation(1/3, spin=1/2)
# Time reversal
TR = qsymm.time_reversal(2, spin=1/2)
# Mirror symmetry in x
Mx = qsymm.mirror([1, 0], spin=1/2)
symmetries = [C3, TR, Mx]

dim = 2  # Momenta along x and y
total_power = 3  # Maximum power of momenta
family = qsymm.continuum_hamiltonian(symmetries, dim, total_power, prettify=True)
qsymm.display_family(family)

## Output
'''
Matrix([[1, 0], [0, 1]])
Matrix([[0, I*k_x + k_y], [-I*k_x + k_y, 0]])
Matrix([[k_x**2 + k_y**2, 0], [0, k_x**2 + k_y**2]])
Matrix([[k_x**3 - 3*k_x*k_y**2, 0], [0, -k_x**3 + 3*k_x*k_y**2]])
Matrix([[0, I*k_x**3 + k_x**2*k_y + I*k_x*k_y**2 + k_y**3], [-I*k_x**3 + k_x**2*k_y - I*k_x*k_y**2 + k_y**3, 0]])
'''

对称操作矩阵为:

[
## C3
PointGroupElement(
R = array([[-0.4999999999999998, -0.8660254037844387],
           [0.8660254037844387, -0.4999999999999998]]),
conjugate = False,
antisymmetry = False,
U = array([[0.5-0.8660254j, 0. +0.j       ],
           [0. +0.j       , 0.5+0.8660254j]])), 
## TR
PointGroupElement(
R = array([[1, 0],
           [0, 1]]),
conjugate = True,
antisymmetry = False,
U = array([[ 0.+0.j, -1.+0.j],
           [ 1.+0.j,  0.+0.j]])), 
## Mx
PointGroupElement(
R = array([[-1, 0],
           [0, 1]]),
conjugate = False,
antisymmetry = False,
U = array([[0.+0.j, 0.-1.j],
           [0.-1.j, 0.+0.j]]))
]
View Code

 

kdotp_symmetry程序运行: 

import sympy as sp
from sympy.core.numbers import I
import sympy.physics.matrices as sm
from sympy.physics.quantum import TensorProduct
import symmetry_representation as sr
import kdotp_symmetry as kp
# In this project we used the basis of tensor products of Pauli matrices
pauli_vec = [sp.eye(2), *(sm.msigma(i) for i in range(1, 4))]
basis = pauli_vec

# creating the symmetry operations
C3 = sr.SymmetryOperation(
    rotation_matrix=sp.Matrix([[-0.5, -0.8660254037844387],[0.8660254037844387, -0.5]]),
    repr_matrix=sp.Matrix([[0.5-0.8660254037844387j, 0 ],[0, 0.5+0.8660254037844387j]]),
    repr_has_cc=False,
    numeric=False
)
time_reversal = sr.SymmetryOperation(
    rotation_matrix=sp.eye(2),
    repr_matrix=sp.Matrix([[0, -1], [1, 0]]),
    repr_has_cc=True,
)
Mx = sr.SymmetryOperation(
    rotation_matrix=sp.Matrix([[-1,0],[0,1]]),
    repr_matrix=sp.Matrix([[0, -1j], [-1j, 0]]),
    repr_has_cc=False,
)

def print_result(order):
    """prints the basis for a given order of k"""
    print('Order:', order)
    for m in kp.symmetric_hamiltonian(
        C3,
        time_reversal,
        Mx,
        expr_basis=kp.monomial_basis(order),
        repr_basis=basis
        ):
        print(m)
    print()

if __name__ == '__main__':
    for i in range(2):
        print_result(order=i)

代码出现报错,还没解决!!!,报错内容如下:

Order: 0
Traceback (most recent call last):
  File "D:\文档\研究生\kp-TB\kdotp_symmetry\kdotp_symmetry_Bi2Se3_surface.py", line 44, in <module>
    print_result(order=i)
  File "D:\文档\研究生\kp-TB\kdotp_symmetry\kdotp_symmetry_Bi2Se3_surface.py", line 32, in print_result
    for m in kp.symmetric_hamiltonian(
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\kdotp_symmetry\_symmetric_hamiltonian.py", line 75, in symmetric_hamiltonian
    operator=matrix_to_expr_operator(
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\kdotp_symmetry\_expr_utils.py", line 105, in matrix_to_expr_operator
    substitution = list(zip(K_VEC, k_matrix_form @ sp.Matrix(K_VEC)))
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\sympy\core\decorators.py", line 106, in binary_op_wrapper
    return func(self, other)
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\sympy\matrices\common.py", line 2740, in __matmul__
    return self.__mul__(other)
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\sympy\core\decorators.py", line 106, in binary_op_wrapper
    return func(self, other)
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\sympy\matrices\common.py", line 2774, in __mul__
    return self.multiply(other)
  File "C:\Users\ghzph\AppData\Roaming\Python\Python310\site-packages\sympy\matrices\common.py", line 2796, in multiply
    raise ShapeError("Matrix size mismatch: %s * %s." % (
sympy.matrices.common.ShapeError: Matrix size mismatch: (2, 2) * (3, 1).
View Code

-2021.09.04 已找到错误原因:

查看 kdotp_symmetry 源码发现,该程序只针对以 kx, ky, kz 三个 k 参数展开的基矢,对于想只操作只含  kx,ky 的哈密顿量,需要改动python 源码。

 

 

例子2: BHZ model

We reproduce the Hamiltonian for the quantum spin Hall effect derived in Science, 314, 1757 (2006).

The symmetry group is generated by spatial inversion symmetry, time-reversal symmetry and fourfold rotation symmetry.

import numpy as np
import sympy
import qsymm

# Spatial inversion
pU = np.array([
    [1.0, 0.0, 0.0, 0.0],
    [0.0, -1.0, 0.0, 0.0],
    [0.0, 0.0, 1.0, 0.0],
    [0.0, 0.0, 0.0, -1.0],
])
pS = qsymm.inversion(2, U=pU)

# Time reversal
trU = np.array([
    [0.0, 0.0, -1.0, 0.0],
    [0.0, 0.0, 0.0, -1.0],
    [1.0, 0.0, 0.0, 0.0],
    [0.0, 1.0, 0.0, 0.0],
])
trS = qsymm.time_reversal(2, U=trU)

# Rotation
phi = 2.0 * np.pi / 4.0  # Impose 4-fold rotational symmetry
rotU = np.array([
    [np.exp(-1j*phi/2), 0.0, 0.0, 0.0],
    [0.0, np.exp(-1j*3*phi/2), 0.0, 0.0],
    [0.0, 0.0, np.exp(1j*phi/2), 0.0],
    [0.0, 0.0, 0.0, np.exp(1j*3*phi/2)],
])
rotS = qsymm.rotation(1/4, U=rotU)

symmetries = [rotS, trS, pS]
# print(symmetries)
dim = 2
total_power = 2

family = qsymm.continuum_hamiltonian(symmetries, dim, total_power, prettify=True)
qsymm.display_family(family)

### Output
'''
Matrix([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]])
Matrix([[0, k_x + I*k_y, 0, 0], [k_x - I*k_y, 0, 0, 0], [0, 0, 0, -k_x + I*k_y], [0, 0, -k_x - I*k_y, 0]])
Matrix([[0, I*k_x - k_y, 0, 0], [-I*k_x - k_y, 0, 0, 0], [0, 0, 0, I*k_x + k_y], [0, 0, -I*k_x + k_y, 0]])
Matrix([[k_x**2 + k_y**2, 0, 0, 0], [0, 0, 0, 0], [0, 0, k_x**2 + k_y**2, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, k_x**2 + k_y**2, 0, 0], [0, 0, 0, 0], [0, 0, 0, k_x**2 + k_y**2]])
'''

表示矩阵

[
PointGroupElement(
R = array([[0, -1],
           [1, 0]]),
conjugate = False,
antisymmetry = False,
U = array([[ 0.70710678-0.70710678j,  0.        +0.j        ,
             0.        +0.j        ,  0.        +0.j        ],
           [ 0.        +0.j        , -0.70710678-0.70710678j,
             0.        +0.j        ,  0.        +0.j        ],
           [ 0.        +0.j        ,  0.        +0.j        ,
             0.70710678+0.70710678j,  0.        +0.j        ],
           [ 0.        +0.j        ,  0.        +0.j        ,
             0.        +0.j        , -0.70710678+0.70710678j]])), 
PointGroupElement(
R = array([[1, 0],
           [0, 1]]),
conjugate = True,
antisymmetry = False,
U = array([[ 0.,  0., -1.,  0.],
           [ 0.,  0.,  0., -1.],
           [ 1.,  0.,  0.,  0.],
           [ 0.,  1.,  0.,  0.]])), 
PointGroupElement(
R = array([[-1, 0],
           [0, -1]]),
conjugate = False,
antisymmetry = False,
U = array([[ 1.,  0.,  0.,  0.],
           [ 0., -1.,  0.,  0.],
           [ 0.,  0.,  1.,  0.],
           [ 0.,  0.,  0., -1.]]))]
View Code

 

kdotp_symmetry:

import sympy as sp
from sympy.core.numbers import I
import sympy.physics.matrices as sm
from sympy.physics.quantum import TensorProduct
import symmetry_representation as sr

import kdotp_symmetry as kp

# In this project we used the basis of tensor products of Pauli matrices
pauli_vec = [sp.eye(2), *(sm.msigma(i) for i in range(1, 4))]
basis = [TensorProduct(p1, p2) for p1 in pauli_vec for p2 in pauli_vec]

# creating the symmetry operations
parity = sr.SymmetryOperation(
    rotation_matrix=sp.Matrix([[-1,0],[0,-1]]),
    repr_matrix=sp.Matrix([[1,0,0,0],
        [0,-1,0,0],
        [0,0, 1,0],
        [0,0,0,-1]]),
    repr_has_cc=False,
)

time_reversal = sr.SymmetryOperation(
    rotation_matrix=sp.eye(2),
    repr_matrix=sp.Matrix([[0,0,-1,0],
        [0,0,0,-1],
        [1,0,0,0],
        [0,1,0,0]]),
    repr_has_cc=True,
)

C4 = sr.SymmetryOperation(
    rotation_matrix=sp.Matrix([[0,-1],[1,0]]),
    repr_matrix=sp.Matrix([[0.7071067811865476-0.7071067811865476j,0,0,0],
        [0,-0.7071067811865476-0.7071067811865476j,0,0],
        [0,0, 0.7071067811865476+0.7071067811865476j,0],
        [0,0,0,-0.7071067811865476+0.7071067811865476j]]),
    repr_has_cc=False,
    # numeric=True
)

def print_result(order):
    """prints the basis for a given order of k"""
    print('Order:', order)
    for m in kp.symmetric_hamiltonian(
        parity,
        time_reversal,
        C4,
        expr_basis=kp.monomial_basis(order),
        repr_basis=basis
    ):
        print(m)
    print()

if __name__ == '__main__':
    # print(c2y)
    for i in range(3):
        print_result(order=i)

运行报错!!!,报错内容如下

ValueError: Input matrix is not unitary: Matrix([[0.707106781186548 - 0.707106781186548*I, 0, 0, 0], [0, -0.707106781186548 - 0.707106781186548*I, 0, 0], [0, 0, 0.707106781186548 + 0.707106781186548*I, 0], [0, 0, 0, -0.707106781186548 + 0.707106781186548*I]])
View Code

2022.09.04 发现问题原因: 

实际上这个矩阵的确是 unitary 的,kdotp_symmetry 程序没有判断出来,这是该程序的一个小bug。

 

例子3: TaAs2

该例子是 kdotp_symmetry 给出的例子: Example code for TaAs2 — kdotp-symmetry 1.0.1 documentation (greschd.ch),之后用 Qsymm 程序来进行验证。

kdotp_symmetry 程序

import sympy as sp
from sympy.core.numbers import I
import sympy.physics.matrices as sm
from sympy.physics.quantum import TensorProduct
import symmetry_representation as sr

import kdotp_symmetry as kp
# In this project we used the basis of tensor products of Pauli matrices
pauli_vec = [sp.eye(2), *(sm.msigma(i) for i in range(1, 4))]
basis = [TensorProduct(p1, p2) for p1 in pauli_vec for p2 in pauli_vec]

# creating the symmetry operations
c2y = sr.SymmetryOperation(
    rotation_matrix=[[0, 1, 0], [1, 0, 0], [0, 0, -1]],
    repr_matrix=sp.diag(I, -I, I, -I),
    repr_has_cc=False,
    numeric=False
)

parity = sr.SymmetryOperation(
    rotation_matrix=-sp.eye(3),
    repr_matrix=sp.diag(1, 1, -1, -1),
    repr_has_cc=False,
)

time_reversal = sr.SymmetryOperation(
    rotation_matrix=sp.eye(3),
    repr_matrix=TensorProduct(sp.eye(2), sp.Matrix([[0, -1], [1, 0]])),
    repr_has_cc=True,
)

def print_result(order):
    """prints the basis for a given order of k"""
    print('Order:', order)
    for m in kp.symmetric_hamiltonian(
        c2y,
        parity,
        time_reversal,
        expr_basis=kp.monomial_basis(order),
        repr_basis=basis
    ):
        print(m)
    print()

if __name__ == '__main__':
    for i in range(3):
        print_result(order=i)

### Output
'''
Order: 0
Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]])

Order: 1
Matrix([[0, 0, 0, kx - ky], [0, 0, kx - ky, 0], [0, kx - ky, 0, 0], [kx - ky, 0, 0, 0]])
Matrix([[0, 0, 0, -I*kx + I*ky], [0, 0, I*kx - I*ky, 0], [0, -I*kx + I*ky, 0, 0], [I*kx - I*ky, 0, 0, 0]])
Matrix([[0, 0, kx + ky, 0], [0, 0, 0, -kx - ky], [kx + ky, 0, 0, 0], [0, -kx - ky, 0, 0]])
Matrix([[0, 0, -I*kx - I*ky, 0], [0, 0, 0, -I*kx - I*ky], [I*kx + I*ky, 0, 0, 0], [0, I*kx + I*ky, 0, 0]])
Matrix([[0, 0, 0, kz], [0, 0, kz, 0], [0, kz, 0, 0], [kz, 0, 0, 0]])
Matrix([[0, 0, 0, -I*kz], [0, 0, I*kz, 0], [0, -I*kz, 0, 0], [I*kz, 0, 0, 0]])

Order: 2
Matrix([[kx**2 + ky**2, 0, 0, 0], [0, kx**2 + ky**2, 0, 0], [0, 0, kx**2 + ky**2, 0], [0, 0, 0, kx**2 + ky**2]])
Matrix([[kx**2 + ky**2, 0, 0, 0], [0, kx**2 + ky**2, 0, 0], [0, 0, -kx**2 - ky**2, 0], [0, 0, 0, -kx**2 - ky**2]])
Matrix([[kx*ky, 0, 0, 0], [0, kx*ky, 0, 0], [0, 0, kx*ky, 0], [0, 0, 0, kx*ky]])
Matrix([[kx*ky, 0, 0, 0], [0, kx*ky, 0, 0], [0, 0, -kx*ky, 0], [0, 0, 0, -kx*ky]])
Matrix([[kx*kz - ky*kz, 0, 0, 0], [0, kx*kz - ky*kz, 0, 0], [0, 0, kx*kz - ky*kz, 0], [0, 0, 0, kx*kz - ky*kz]])
Matrix([[kx*kz - ky*kz, 0, 0, 0], [0, kx*kz - ky*kz, 0, 0], [0, 0, -kx*kz + ky*kz, 0], [0, 0, 0, -kx*kz + ky*kz]])
Matrix([[kz**2, 0, 0, 0], [0, kz**2, 0, 0], [0, 0, kz**2, 0], [0, 0, 0, kz**2]])
Matrix([[kz**2, 0, 0, 0], [0, kz**2, 0, 0], [0, 0, -kz**2, 0], [0, 0, 0, -kz**2]])
'''

 

Qsymm  运行该例子

import numpy as np
import sympy,sys
import qsymm

# Rotation
rotU = np.array([
    [1j, 0.0, 0.0, 0.0],
    [0.0, -1j, 0.0, 0.0],
    [0.0, 0.0,1j, 0.0],
    [0.0, 0.0, 0.0,-1j],
])
c2yS = qsymm.rotation(1/2, axis=[0,1,0],U=rotU)

# Spatial inversion
pU = np.array([
    [1.0, 0.0, 0.0, 0.0],
    [0.0, 1.0, 0.0, 0.0],
    [0.0, 0.0, -1.0, 0.0],
    [0.0, 0.0, 0.0, -1.0],
])
pS = qsymm.inversion(3, U=pU)

# Time reversal
trU = np.array([
    [0.0,-1.0, 0.0, 0.0],
    [1.0, 0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0,-1.0],
    [0.0, 0.0, 1.0, 0.0],
])
trS = qsymm.time_reversal(3, U=trU)

symmetries = [c2yS, pS, trS]
# print(symmetries)

dim = 3
total_power = 2

family = qsymm.continuum_hamiltonian(symmetries, dim, total_power, prettify=True)
qsymm.display_family(family)

### Output:
'''
Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
Matrix([[0, 0, 0, k_z], [0, 0, k_z, 0], [0, k_z, 0, 0], [k_z, 0, 0, 0]])
Matrix([[0, 0, 0, I*k_z], [0, 0, -I*k_z, 0], [0, I*k_z, 0, 0], [-I*k_z, 0, 0, 0]])
Matrix([[0, 0, 0, k_x], [0, 0, k_x, 0], [0, k_x, 0, 0], [k_x, 0, 0, 0]])
Matrix([[0, 0, 0, I*k_x], [0, 0, -I*k_x, 0], [0, I*k_x, 0, 0], [-I*k_x, 0, 0, 0]])
Matrix([[0, 0, k_y, 0], [0, 0, 0, -k_y], [k_y, 0, 0, 0], [0, -k_y, 0, 0]])
Matrix([[0, 0, I*k_y, 0], [0, 0, 0, I*k_y], [-I*k_y, 0, 0, 0], [0, -I*k_y, 0, 0]])
Matrix([[k_x**2, 0, 0, 0], [0, k_x**2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, k_x**2, 0], [0, 0, 0, k_x**2]])
Matrix([[k_z**2, 0, 0, 0], [0, k_z**2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, k_z**2, 0], [0, 0, 0, k_z**2]])
Matrix([[k_x*k_z, 0, 0, 0], [0, k_x*k_z, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, k_x*k_z, 0], [0, 0, 0, k_x*k_z]])
Matrix([[k_y**2, 0, 0, 0], [0, k_y**2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, k_y**2, 0], [0, 0, 0, k_y**2]])
'''

不难发现,这两个python库得到的结果不同,原因是 Qsymm 求得的 c2y 对称操作矩阵不是按照晶格基矢的

验证:将 kdotp_symmetry 中的 c2y 对称操作矩阵按照 Qsymm 一样,检验二者结果是否相同!

###
# creating the symmetry operations
c2y = sr.SymmetryOperation(
    #rotation_matrix=[[0, 1, 0], [1, 0, 0], [0, 0, -1]],
    rotation_matrix=[[-1, 0, 0], [0, 1, 0], [0, 0, -1]],
    repr_matrix=sp.diag(I, -I, I, -I),
    repr_has_cc=False,
    numeric=False
)
###

Order: 0
Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]])

Order: 1
Matrix([[0, 0, 0, kx], [0, 0, kx, 0], [0, kx, 0, 0], [kx, 0, 0, 0]])
Matrix([[0, 0, 0, -I*kx], [0, 0, I*kx, 0], [0, -I*kx, 0, 0], [I*kx, 0, 0, 0]])
Matrix([[0, 0, ky, 0], [0, 0, 0, -ky], [ky, 0, 0, 0], [0, -ky, 0, 0]])
Matrix([[0, 0, -I*ky, 0], [0, 0, 0, -I*ky], [I*ky, 0, 0, 0], [0, I*ky, 0, 0]])
Matrix([[0, 0, 0, kz], [0, 0, kz, 0], [0, kz, 0, 0], [kz, 0, 0, 0]])
Matrix([[0, 0, 0, -I*kz], [0, 0, I*kz, 0], [0, -I*kz, 0, 0], [I*kz, 0, 0, 0]])

Order: 2
Matrix([[kx**2, 0, 0, 0], [0, kx**2, 0, 0], [0, 0, kx**2, 0], [0, 0, 0, kx**2]])
Matrix([[kx**2, 0, 0, 0], [0, kx**2, 0, 0], [0, 0, -kx**2, 0], [0, 0, 0, -kx**2]])
Matrix([[kx*kz, 0, 0, 0], [0, kx*kz, 0, 0], [0, 0, kx*kz, 0], [0, 0, 0, kx*kz]])
Matrix([[kx*kz, 0, 0, 0], [0, kx*kz, 0, 0], [0, 0, -kx*kz, 0], [0, 0, 0, -kx*kz]])
Matrix([[ky**2, 0, 0, 0], [0, ky**2, 0, 0], [0, 0, ky**2, 0], [0, 0, 0, ky**2]])
Matrix([[ky**2, 0, 0, 0], [0, ky**2, 0, 0], [0, 0, -ky**2, 0], [0, 0, 0, -ky**2]])
Matrix([[kz**2, 0, 0, 0], [0, kz**2, 0, 0], [0, 0, kz**2, 0], [0, 0, 0, kz**2]])
Matrix([[kz**2, 0, 0, 0], [0, kz**2, 0, 0], [0, 0, -kz**2, 0], [0, 0, 0, -kz**2]])

该结果和 Qsymm 得出的一致。

 综上可以发现:

kdotp_symmetry python 库仍存在一些 bug,以后要谨慎使用。

posted @ 2022-09-03 21:44  ghzphy  阅读(368)  评论(0编辑  收藏  举报