# -*- coding: utf-8 -*-
"""
Created on Wed Dec 3 15:00:14 2014
@author: Matti Ropo
@author: Henrik Levämäki
"""
from __future__ import print_function
import sys
import datetime
import numpy as np
import pyemto.common.common as common
from pyemto.c import c_lattice
[docs]class Kstr:
"""Contains information about KSTR input files for EMTO 5.8 program
:param jobname_lat: (Default value = None)
:type jobname_lat:
:param lat: (Default value = None)
:type lat:
:param latparams: (Default value = None)
:type latparams:
:param ca: (Default value = None)
:type ca:
:param latvectors: (Default value = None)
:type latvectors:
:param basis: (Default value = None)
:type basis:
:param kappaw: (Default value = None)
:type kappaw:
:param dmax: (Default value = None)
:type dmax:
:param msgl: (Default value = None)
:type msgl:
:param nprn: (Default value = None)
:type nprn:
:param lamda: (Default value = None)
:type lamda:
:param amax: (Default value = None)
:type amax:
:param bmax: (Default value = None)
:type bmax:
:param nqr2: (Default value = None)
:type nqr2:
:param mode: (Default value = None)
:type mode:
:param store: (Default value = None)
:type store:
:param high: (Default value = None)
:type high:
:param kstr_nl: (Default value = None)
:type kstr_nl:
:param nlh: (Default value = None)
:type nlh:
:param nlw: (Default value = None)
:type nlw:
:param nder: (Default value = None)
:type nder:
:param itrans: (Default value = None)
:type itrans:
:param rwats: (Default value = None)
:type rwats:
:param nghbp: (Default value = None)
:type nghbp:
:param awIQ: (Default value = None)
:type awIQ:
:returns: None
:rtype: None
"""
def __init__(self, jobname_lat=None, lat=None, latparams=None, ca=None,
latvectors=None, basis=None, kappaw=None, dmax=None,
msgl=None, nprn=None, lamda=None, amax=None,
bmax=None, nqr2=None, mode=None, store=None, high=None,
kstr_nl=None, nlh=None, nlw=None, nder=None, itrans=None,
rwats=None, nghbp=None, awIQ=None, numvec_target=None):
# Argument checking and default values
self.lat = lat
self.jobname_lat = jobname_lat
self.latparams = latparams
self.latvectors = latvectors
if basis is None:
self.basis = None
else:
self.basis = np.asarray(basis)
self.kappaw = kappaw
self.dmax = dmax
self.msgl = msgl
self.nprn = nprn
self.lamda = lamda
self.amax = amax
self.bmax = bmax
self.nqr2 = nqr2
self.mode = mode
self.store = store
self.high = high
self.kstr_nl = kstr_nl
self.nlh = nlh
self.nlw = nlw
self.nder = nder
self.itrans = itrans
self.rwats = rwats
self.nghbp = nghbp
self.ca = ca # hcp's c/a ratio
self.awIQ = awIQ
self.numvec_target = numvec_target
[docs] def output(self, index):
"""Outputs KSTR input file as a formatted string.
:param index:
:type index:
:returns: KSTR input file string
:rtype: str
"""
slope = 'kstr/'
prn = 'kstr/'
boolean = {True: "Y", False: "N"}
if index == 1:
kappaw = self.kappaw[0]
jobname_lat = self.jobname_lat
elif index == 2:
kappaw = self.kappaw[1]
jobname_lat = self.jobname_lat2
now = datetime.datetime.now()
line = "KSTR HP......=N "\
+ str(now.day) + "." + str(now.month) + "." + str(now.year) + "\n"
JOBNAMline = "JOBNAM...=" + jobname_lat
MSGLline = "MSGL.= " + str(self.msgl)
line = line + "{0:21s}{1:9s}".format(JOBNAMline, MSGLline) +\
" MODE...={0} STORE..={1} HIGH...={2}"\
.format(self.mode, self.store, self.high) + "\n"
line = line + "DIR001=" + slope + "\n"
line = line + "DIR006=" + prn + "\n"
line = line + "Slope matrices, {0:10}, (kappa*w)^2= {1:5.1f}"\
.format(jobname_lat, kappaw) + "\n"
line = line + "NL.....={0:2d} NLH...={1:2d} NLW...={2:2d} "\
.format(self.kstr_nl, self.nlh, self.nlw) +\
"NDER..={0:2d} ITRANS={1:2d} NPRN..={2:2d}"\
.format(self.nder, self.itrans, self.nprn) + "\n"
line = line + "(K*W)^2..={0:10.6f} DMAX....={1:10.4f} RWATS...={2:10.2f}"\
.format(kappaw, self.dmax, self.rwats) + "\n"
line = line + "NQ3...={0:3d} LAT...={1:2d} IPRIM.={2:2d} NGHBP.={3:2d} NQR2..={4:2d}"\
.format(self.nq, common.lat_to_ibz(self.lat), self.iprim, self.nghbp, self.nqr2) + "\n"
line = line + "A........={0:10.8f} B.......={1:10.8f} C.......={2:10.8f}"\
.format(self.latparams[0], self.latparams[1], self.latparams[2]) + "\n"
if self.iprim == 1:
line = line + "ALPHA....={0:10.6f} BETA....={1:10.6f} GAMMA...={2:10.6f}"\
.format(self.latvectors[0], self.latvectors[1], self.latvectors[2]) + "\n"
elif self.iprim == 0:
line = line + "BSX......={0:10.7f} BSY.....={1:10.7f} BSZ.....={2:10.7f}"\
.format(self.latvectors[0][0], self.latvectors[0][1], self.latvectors[0][2]) + "\n"
line = line + "BSX......={0:10.7f} BSY.....={1:10.7f} BSZ.....={2:10.7f}"\
.format(self.latvectors[1][0], self.latvectors[1][1], self.latvectors[1][2]) + "\n"
line = line + "BSX......={0:10.7f} BSY.....={1:10.7f} BSZ.....={2:10.7f}"\
.format(self.latvectors[2][0], self.latvectors[2][1], self.latvectors[2][2]) + "\n"
for i in range(self.nq):
#line = line + "QX.......={0:10.7f} QY......={1:10.7f} QZ(...={2:10.7f}"\
line = line + "QX({3:03})..={0:10.7f} QY({3:03}).={1:10.7f} QZ({3:03}).={2:10.7f}"\
.format(self.basis[i,0], self.basis[i,1], self.basis[i,2], i+1) + "\n"
aw_template = "a/w(IQ)..="
for i in range(self.kstr_nl):
aw_template += f" {{{i}:4.2f}}"
for i in range(self.nq):
# line = line + "a/w(IQ)..= {0:4.2f} {1:4.2f} {2:4.2f} {3:4.2f}"\
# .format(*self.awIQ[i, :]) + "\n"
line = line + aw_template.format(*self.awIQ[i, :]) + "\n"
line = line + "LAMDA....={0:10.7f} AMAX....={1:10.7f} BMAX....={2:10.7f}"\
.format(self.lamda, self.amax, self.bmax) + "\n"
return line
[docs] def set_values(self, key, value):
"""Set input parameter values.
:param key:
:type key:
:param value:
:type value:
:returns: None
:rtype: None
"""
if hasattr(self, key):
setattr(self, key, value)
if key == 'ca' and self.lat == 'hcp':
# c/a has changed => update lattice parameters
self.latparams = [1.0, 1.0, self.ca]
self.latvectors = [
[1.0, 0.0, 0.0], [-0.5, 0.8660254, 0.0], [0.0, 0.0, self.ca]]
self.basis = np.asarray([
[0.0, 0.0, 0.0], [0.0, 0.57735027, self.ca / 2.0]])
else:
print('WARNING: Kstr() class has no attribute \'{0}\''.format(key))
return
[docs] def generate_prims(self,angles):
"""Generates the primitive lattice vectors from the angle and Bravais-lattice
type information.
"""
deg_to_rad = np.pi/180.0
alpha = angles[0] * deg_to_rad
beta = angles[1] * deg_to_rad
gamma = angles[2] * deg_to_rad
ibz = common.lat_to_ibz(self.lat)
boa = self.latparams[1]/self.latparams[0]
coa = self.latparams[2]/self.latparams[0]
#
if ibz == 1:
prims = np.array([[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]])
elif ibz == 2:
prims = np.array([[0.5,0.5,0.0],[0.0,0.5,0.5],[0.5,0.0,0.5]])
elif ibz == 3:
prims = np.array([[0.5,0.5,-0.5],[-0.5,0.5,0.5],[0.5,-0.5,0.5]])
elif ibz == 4:
prims = np.array([[1.0,0.0,0.0],[-0.5,0.5*np.sqrt(3.0),0.0],[0.0,0.0,coa]])
elif ibz == 5:
prims = np.array([[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,coa]])
elif ibz == 6:
prims = np.array([[-0.5,0.5,0.5*coa],[0.5,-0.5,0.5*coa],[0.5,0.5,-0.5*coa]])
elif ibz == 7:
prims = np.array([[0.0,1.0,coa],[-0.5*np.sqrt(3.0),-0.5,coa],[0.5*np.sqrt(3.0),-0.5,coa]])
elif ibz == 8:
prims = np.array([[1.0,0.0,0.0],[0.0,boa,0.0],[0.0,0.0,coa]])
elif ibz == 9:
prims = np.array([[0.5,-0.5*boa,0.0],[0.5,0.5*boa,0.0],[0.0,0.0,coa]])
elif ibz == 10:
prims = np.array([[0.5,-0.5*boa,0.5*coa],[0.5,0.5*boa,-0.5*coa],[-0.5,0.5*boa,0.5*coa]])
elif ibz == 11:
prims = np.array([[0.5,0.0,0.5*coa],[0.5,0.5*boa,0.0],[0.0,0.5*boa,0.5*coa]])
elif ibz == 12:
prims = np.array([[1.0,0.0,0.0],[boa*np.cos(gamma),boa*np.sin(gamma),0.0],
[0.0,0.0,coa]])
elif ibz == 13:
prims = np.array([[0.0,-boa,0.0],[0.5*np.sin(gamma),-0.5*np.cos(gamma),-0.5*coa],
[0.5*np.sin(gamma),-0.5*np.cos(gamma),0.5*coa]])
elif ibz == 14:
tmp1 = (np.cos(alpha)-np.cos(beta)*np.cos(gamma))/np.sin(gamma)
tmp2 = np.sqrt((1.0-np.cos(gamma)**2-np.cos(alpha)**2-np.cos(beta)**2
+2.0*np.cos(alpha)*np.cos(beta)*np.cos(gamma)))/np.sin(gamma)
prims = np.array([[1.0,0.0,0.0],[boa*np.cos(gamma),boa*np.sin(gamma),0.0],
[coa*np.cos(beta),coa*tmp1,coa*tmp2]])
#print('generated prims:')
#print(prims)
return prims
[docs] def compute_num_of_vecs(self,prims,basis,nghbp,dmax):
"""Computes the number of vectors for a given dmax value."""
ncrq = 0
nq = self.nq
#
qix = basis[0,0]
qiy = basis[0,1]
qiz = basis[0,2]
#
for jq in range(nq):
qmqpx=basis[jq,0]-qix
qmqpy=basis[jq,1]-qiy
qmqpz=basis[jq,2]-qiz
for l in range(-nghbp,nghbp+1):
for m in range(-nghbp,nghbp+1):
for n in range(-nghbp,nghbp+1):
sx=qmqpx+l*prims[0,0]+m*prims[1,0]+n*prims[2,0]
sy=qmqpy+l*prims[0,1]+m*prims[1,1]+n*prims[2,1]
sz=qmqpz+l*prims[0,2]+m*prims[1,2]+n*prims[2,2]
dx=np.sqrt(sx*sx+sy*sy+sz*sz)
if dx <= dmax:
ncrq += 1
#print('DX,NCRQ = ',dx,ncrq)
return ncrq
[docs] def optimize_dmax(self,prims,basis):
"""Calculates the best possible dmax value, which gives the closest number
of vectors given some target value (which is typically 80-90)."""
# Check if primitive vectors have been
# explicitly given (iprim = 0).
# If not (iprim = 1), we have to generate
# from the alpha, beta, and gamma + ibz
# information
#print('basis:')
#print(basis)
if self.iprim == 0:
prims = np.asarray(prims)
basis = np.asarray(basis)
# Take the first site as the origin
basis[:,0] -= basis[0,0]
basis[:,1] -= basis[0,1]
basis[:,2] -= basis[0,2]
elif self.iprim == 1:
prims = self.generate_prims(prims)
basis = np.asarray(basis)
# Take the first site as the origin
basis[:,0] -= basis[0,0]
basis[:,1] -= basis[0,1]
basis[:,2] -= basis[0,2]
#print(prims)
#print(basis)
#
nghbp = self.nghbp
dmax_min = 0.5
dmax_max = 8.0
ncrq_target = self.numvec_target
tol_target = 1.0e-4
# Initial dmax guess
dmax_mid_old = 1000.0
dmax_mid = np.round((dmax_max + dmax_min)/2,4)
f_closest = 1000
#
print('Latticeinputs.Kstr.optimize_dmax(): Optimizing dmax (target = {0:3d}) for {1}...'
.format(ncrq_target,self.jobname_lat))
#
while np.abs(dmax_mid_old - dmax_mid) > tol_target:
# Compute the number of vectors that
# corresponds to the trial choice of dmax
# ncrq = Number of vectors for the first site
# in the basis, which has been shifted to lie
# in the origin.
#f_mid = self.compute_num_of_vecs(prims,basis,nghbp,dmax_mid)
f_mid = c_lattice.compute_num_of_vecs(prims,basis,nghbp,dmax_mid,self.nq)
#
if f_mid == ncrq_target:
# Target number of vectors has been reached exactly
dmax_closest = dmax_mid
f_closest = f_mid
break
elif f_mid - ncrq_target < 0:
# Number of vectors too small
if np.abs(f_mid-ncrq_target) < np.abs(f_closest-ncrq_target):
dmax_closest = dmax_mid
f_closest = f_mid
dmax_min = dmax_mid
else:
# Number of vectors too large.
if np.abs(f_mid-ncrq_target) < np.abs(f_closest-ncrq_target):
dmax_closest = dmax_mid
f_closest = f_mid
elif np.abs(f_mid-ncrq_target) == np.abs(f_closest-ncrq_target):
if f_mid > f_closest:
dmax_closest = dmax_mid
f_closest = f_mid
dmax_max = dmax_mid
#
dmax_mid_old = dmax_mid
dmax_mid = np.round((dmax_max + dmax_min)/2,4)
#print('dmax, Number of vectors: {0:6.4f}, {1}'.format(dmax_mid_old,f_mid))
print('dmax, Number of vectors: {0:6.4f}, {1}'.format(dmax_closest,f_closest))
return dmax_closest, f_closest
[docs] def finalize(self):
"""Re-initializes input parameters."""
self.awIQ = None
#self.dmax = None
#self.kappaw = None
#self.jobname_lat = None
#self.latparams = None
#self.latvectors = None
#self.basis = None
return