晶胞之间相互转换

固体物理中经常会涉及到两种晶胞的选取方式,一种叫primitive cell(原胞),另一种叫conventional cell(单胞,惯用晶胞)。有些工具已经帮我们实现了这两种晶胞的转换。

晶胞转换方法

phonopy晶胞转换

phonopy --symmetry POSCAR

phonopy判断的阈值比较小,有时候可以设置大一点

phonopy --symmetry --tolerance=1.0e-3 POSCAR

POSCAR是VASP输入格式的晶胞。执行命令后会生成BPOSCAR(conventional cell)和PPOSCAR(primitive cell)。

Avogadro晶胞转换

安装后导入结构,执行Crystallography ->Reduce->Reduce Cell(primitive cell),当然,有时候也要设置阈值 Crystallography ->Settings->Tolerance for symmetry operations

QEtoolkit

这个网页集成的功能基于spglib的,当然前面的phonopy也是。

AFLOW

这个网站功能比较强大。

Spglib库使用

下面介绍怎么用spglib库的功能实现晶胞转换。
首先是读取结构文件(read_poscar.py)

import spglib
import numpy as np
import os
import linecache

class read_poscar(object):
    def __init__(
        self,
        struct=None,
        pos_name=None,
        lattice_index=None,
        lat=None,
        lat_recell=None,
        atomname=None,
        atomnum=None,
        postype=None,
        pos=None,
        spg_number=None,
    ):
        self.struct = linecache.getlines("POSCAR")
        # read POSCAR to get some paramatrics: sys_name; lattice; atom_name; atom_number; atom_position
        # and get spacegroup_number
        poscar = [line.strip() for line in self.struct]
        num = len(poscar)

        self.pos_name = poscar[0].split()
        self.lat_index = poscar[1].split()
        self.lattice_index = float(self.lat_index[0])

        # matrics of lattice vector

        lat_vector = np.zeros((3, 3))
        index = 0
        for latt in poscar[2:5]:
            latt = latt.split()
            lat_vector[index, :] = latt[0:3]
            index += 1
        self.lattice = lat_vector

        self.atomname = poscar[5].split()
        self.atomnum = poscar[6].split()
        self.postype = poscar[7].split()

        atom_len=len(self.atomname)

        # matrics of atom position

        i = num - 8
        position_vector = np.zeros((i, 3))
        index = 0
        for poss in poscar[8:num]:
            poss = poss.split()
            #position_vector[index, 0:3] = poss[0:3]
            position_vector[index,0] = poss[0]
            position_vector[index,1] = poss[1]
            position_vector[index,2] = poss[2]
            index += 1

        self.lat = lat_vector * self.lattice_index
        self.pos = position_vector
        atom_numbers = [1,] * (int(self.atomnum[0]))#+int(self.atomnum[1]))
        cell = (self.lat, self.pos, atom_numbers)
        database = spglib.get_symmetry_dataset(
            cell, symprec=1e-3
        )
        self.spg_number = database["number"]

    def system_name(self):
        return self.pos_name

    def latt_index(self):
        return self.lattice_index

    def latti(self):
        return self.lattice

    def atom_name(self):
        return self.atomname

    def atom_number(self):
        return self.atomnum

    def position_type(self):
        return self.postype

    def positions(self):
        return self.pos

    def spacegroup_num(self):
        return self.spg_number

然后转换晶胞

import os
import numpy as np
import read_poscar as readpos
import spglib

class recell(object):
    def __init__(
        self,
        spg_num=None,
        lattindex=None,
        latt=None,
        atomname=None,
        atomnum=None,
        postype=None,
        position=None,
        cell_lattice=None,
        cell_position=None,
        cell_atomnum=None,
        to_pricell = None
    ):
        # read the origmitive cell
        self.spg_num = readpos.read_poscar().spacegroup_num()
        self.lattindex = readpos.read_poscar().latt_index()
        self.latt = readpos.read_poscar().latti()
        self.atomname = readpos.read_poscar().atom_name()
        self.atomnum = readpos.read_poscar().atom_number()
        self.postype = readpos.read_poscar().position_type()
        self.position = readpos.read_poscar().positions()

        orignumbers = []
        for i in np.arange(0, len(self.atomname)):
            for j in np.arange(0, int(self.atomnum[i]), 1):
                orignumbers.append(i + 1)

        origlattice = self.latt * self.lattindex
        origpositon = self.position

        origcell = (origlattice, origpositon, orignumbers)

        if(to_pricell==False):

        # refine cell
            self.cell_lattice, re_position, re_numbers = spglib.standardize_cell(
                cell=origcell, symprec=1e-3, to_primitive=False
            )
        else:
            self.cell_lattice, re_position, re_numbers = spglib.standardize_cell(
                cell=origcell, symprec=1e-3, to_primitive=True
            )



        # 主要对坐标进行重新排序
        re_position_list = list(re_position)
        zipped = list(zip(re_numbers, re_position_list))
        zipsorted = sorted(zipped, key=lambda x: (x[0]))

        re_numbers_sort, re_positon_sort = zip(*zipsorted)

        self.cell_position = np.array(re_positon_sort)

        self.cell_atomnum = []
        for i in np.arange(0, len(self.atomnum), 1):
            num = int(self.atomnum[i]) * (len(re_numbers_sort) / len(orignumbers))
            self.cell_atomnum.append(num)

        # write the refine cell

        writepos = open("RECELL", mode="w")
        print("recell_poscar", file=writepos)
        print("1.0", file=writepos)

        for m in np.arange(0, 3, 1):
            print(
                format(self.cell_lattice[m, 0], ".10f"),
                "   ",
                format(self.cell_lattice[m, 1], ".10f"),
                "   ",
                format(self.cell_lattice[m, 2], ".10f"),
                file=writepos,
            )

        for j in np.arange(0, len(self.atomname), 1):
            print(self.atomname[j], file=writepos, end=" ")
        print(end="\n", file=writepos)
        for l in np.arange(0, len(self.atomname), 1):
            print(int(self.cell_atomnum[l]), end=" ", file=writepos)
        print(end="\n", file=writepos)
        print(self.postype[0], file=writepos)

        for n in np.arange(0, self.cell_position.shape[0], 1):
            print(
                format(self.cell_position[n, 0], ".10f"),
                "   ",
                format(self.cell_position[n, 1], ".10f"),
                "   ",
                format(self.cell_position[n, 2], ".10f"),
                file=writepos,
            )
        writepos.close()

    def latti(self):
        return self.cell_lattice

    def atom_number(self):
        return self.cell_atomnum

    def positions(self):
        return self.cell_position

使用方法

import reposcar
reposcar.recell(to_pricell=False) #转化为惯用晶胞
reposcar.recell(to_pricell=True)  #转化为原胞

   转载规则


《晶胞之间相互转换》 ZSaying 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录