phonopy/scripts/phonopy-crystal-born

145 lines
5.7 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright (C) 2018 Antti Karttunen (antti.j.karttunen@iki.fi)
# All rights reserved.
#
# This file is part of phonopy.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# * Neither the name of the phonopy project nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import sys
import numpy as np
def get_options():
# Parse options
import argparse
parser = argparse.ArgumentParser(
description="Phonopy crystal-born command-line-tool")
parser.add_argument(
"filename", nargs='*',
help="Filename: CRYSTAL output file (default: crystal.o)")
args = parser.parse_args()
return args
def read_crystal_epsilon(epscol, epslines):
# XX, XY, XZ, YY, YZ, ZZ are given (6 rows). YX = XY, ZX = XZ, ZY = YZ
# Format for CRYSTAL17 (epscol == 4):
# 0.000 XX 57.1760 0.0000 3.2117 0.0000 2.2117
# Format for CRYSTAL14 (epscol == 3):
# XX 57.1760 0.0000 3.2117 2.2117
eps = [] # Will have 9 elements 0..8
eps.append(float(epslines[0].split()[epscol])) # XX (0)
eps.append(float(epslines[1].split()[epscol])) # XY (1)
eps.append(float(epslines[2].split()[epscol])) # XZ (2)
eps.append(eps[1]) # YX = XY (3)
eps.append(float(epslines[3].split()[epscol])) # YY (4)
eps.append(float(epslines[4].split()[epscol])) # YZ (5)
eps.append(eps[2]) # ZX = XZ (6)
eps.append(eps[5]) # ZY = YZ (7)
eps.append(float(epslines[5].split()[epscol])) # ZZ (8)
return eps
def main(args):
if args.filename:
crystal_filename = args.filename[0]
else:
crystal_filename = "crystal.o"
# Read in the output file
try:
with open(crystal_filename, "r") as crystal_file:
lines = crystal_file.readlines()
except OSError:
print("CRYSTAL output file {} cannot be opened for reading".format(crystal_filename))
sys.exit(1)
# Recommended CRYSTAL calculation type:
# Gamma-point FREQCALC with INTCPHF and INTENS
# The file will include both dielectric tensor and effective Born charges
epsilon = []
zeff = []
l = 0
while l < len(lines):
line = lines[l]
# Parse the information about atoms
if 'PRIMITIVE CELL - CENTRING CODE' in line:
l += 4
# ATOMS IN THE ASYMMETRIC UNIT 2 - ATOMS IN THE UNIT CELL: 6
N_asym_atoms = int(lines[l].split()[5])
N_atoms = int(lines[l].split()[12])
l += 3
# Check for each atom if it belongs to the asymmetric unit
# 1 T 22 TI 4.721218104494E-21 3.307446203077E-21 1.413771901417E-21
is_asym = []
for atom in range(0, N_atoms):
atomdata = lines[l].split()
is_asym.append(atomdata[1])
l += 1
# Parse dielectric tensor from INTCPHF
elif 'FR.(eV) COMP. ALPHA(Re,Im) EPSILON(Re,Im)' in line:
# CRYSTAL17
epsilon = read_crystal_epsilon(4, lines[l+1:l+7])
l += 7
elif 'COMPONENT ALPHA(REAL, IMAGINARY) EPSILON CHI(1)' in line:
epsilon = read_crystal_epsilon(3, lines[l+1:l+7])
l += 7
# Parse Born charges
elif 'ATOMIC BORN CHARGE TENSOR' in line:
l += 6
for atom in range(0, N_atoms):
if is_asym[atom] == 'T':
zeffatom = []
for i in range(0, 3):
# 1 8.3860E-01 3.4861E-01 3.4861E-01
zeffatom += [float(x) for x in lines[l].split()[1:4]]
l += 1
zeff.append(zeffatom)
l += 4
else:
l += 7
l += 1 # while l < len(lines)
# Output BORN if epsilon and zeff are available
if len(epsilon) == 9 and len(zeff) == N_asym_atoms:
# Conversion factor
bornlines = ("default\n")
# Dielectric tensor
bornlines += ("%6.4f " * 9 + "\n") % tuple(epsilon)
# Effective charges
for atom in range(0, N_asym_atoms):
bornlines += ("%6.4f " * 9 + "\n") % tuple(zeff[atom])
print(bornlines, end='')
if __name__ == "__main__":
main(get_options())