Skip to content

Commit

Permalink
Proper treatment of symmetry for cubic crystals.
Browse files Browse the repository at this point in the history
Other symmetries not implemented but skeleton exists.
  • Loading branch information
jochym committed Jan 6, 2014
1 parent f53a776 commit a006ace
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*.so

# Packages
MANIFEST
*.egg
*.egg-info
dist
Expand Down
8 changes: 6 additions & 2 deletions qeutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class QuantumEspresso(FileIOCalculator):
default_parameters = {
'calc':'scf',
'outdir': 'tmp',
'wfcdir': 'tmp',
'asr':'crystal',
'pseudo_dir': '../pspot',
'ndos': 200,
Expand All @@ -66,7 +67,10 @@ class QuantumEspresso(FileIOCalculator):
'ecutwfc': 50,
'ibrav': 0,
'pp_type': 'nc',
'pp_format': 'ncpp'
'pp_format': 'ncpp',
'use_symmetry': False,
'kpt_type': 'automatic',
'kpt_shift': [0,0,0]
}
'Default parameters'

Expand All @@ -76,7 +80,7 @@ def __init__(self,label=None,atoms=None, wdir='./', **kwargs):
self.prefix=label
self.directory=make_calc_dir(self.prefix,wdir)
self.submited=False
print self.directory
self.use_symmetry=self.parameters['use_symmetry']

def calculate(self, atoms=None, properties=['energy'],
system_changes=all_changes):
Expand Down
138 changes: 122 additions & 16 deletions qeutil/writers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from tempfile import mkdtemp

import os
from tempfile import mkdtemp
from pyspglib import spglib
from numpy.linalg import norm
from math import sqrt
from ase import Atoms

# PWscf input file
pw_in='''
Expand Down Expand Up @@ -69,6 +74,9 @@
/
'''




def write_section_params(fh, k, p):
""" Automatically writes all the specified parameters for this section.
Multidimensional parameters are taken into account properly.
Expand Down Expand Up @@ -101,68 +109,166 @@ def write_section_params(fh, k, p):
elif isinstance(value, basestring):
fh.write(" %s = '%s',\n" % (key, value))

bravais_lattice_to_ibrav = {"free":0,
"cubic p (sc)": 1,
"cubic f (fcc)": 2,
"cubic i (bcc)": 3,
"hexagonal and trigonal p": 4,
"trigonal r": 5,
"tetragonal p (st)": 6,
"tetragonal i (bct)": 7,
"orthorhombic p": 8,
"orthorhombic base-centered(bco)": 9,
"orthorhombic face-centered": 10,
"orthorhombic body-centered": 11,
"monoclinic p": 12,
"monoclinic base-centered": 13,
"triclinic p": 14}


def write_cell_params(fh, a, p):
'''
Write the specification of the cell using a traditional A,B,C,
alpha, beta, gamma scheme. The symmetry and parameters are determined
from the atoms (a) object. The atoms object is translated into a
primitive unit cell but *not* converted. This is just an internal procedure.
If you wish to work with primitive unit cells in ASE, you need to make
a conversion yourself. The cell params are in angstrom.
Input
-----
fh file handle of the opened pw.in file
a atoms object
p parameters dictionary
Output
------
Primitive cell tuple of arrays: (lattice, atoms, atomic numbers)
'''

assert(p['use_symmetry'])

# Get a spacegroup name and number for the a
sg,sgn=spglib.get_spacegroup(a).split()
# Extract the number
sgn=int(sgn[1:-1])
# Extract the lattice type
ltyp=sg[0]

# Find a primitive unit cell for the system
# puc is a tuple of (lattice, atoms, atomic numbers)
puc=spglib.find_primitive(a)
cell=puc[0]
apos=puc[1]
anum=puc[2]

# Select appropriate ibrav
if sgn >= 195 :
# Cubic lattice
if ltyp=='P': p['ibrav']=1 # Primitive
elif ltyp=='F': p['ibrav']=2 # FCC
elif ltyp=='I': p['ibrav']=3 # FCC
else :
print 'Impossible lattice symmetry! Contact the author!'
raise NotImplementedError
fh.write(' A = %f,\n' % (sqrt(2)*norm(cell[0]),))
elif sgn >= 143 :
# Hexagonal and trigonal
if ltyp=='P' : p['ibrav']=4 # Primitive
elif ltyp=='R' : p['ibrav']=5 # Trigonal rhombohedral
else :
print 'Impossible lattice symmetry! Contact the author!'
raise NotImplementedError
elif sgn >= 75 :
raise NotImplementedError
else :
raise NotImplementedError
return puc


def write_pw_in(d,a,p):

fh=open(os.path.join(d,'pw.in'),'w')
# ----------------------------------------------------------
# | CONTROL section
# CONTROL section
# ----------------------------------------------------------

fh.write(' &CONTROL\n')
fh.write(" calculation = '%s',\n" % p['calc'])

pwin_k=['tstress','nstep','pseudo_dir','outdir']
pwin_k=['tstress','nstep','pseudo_dir','outdir','wfcdir']
write_section_params(fh, pwin_k, p)
fh.write(' /\n')

# ----------------------------------------------------------
# | SYSTEM section
# SYSTEM section
# ----------------------------------------------------------

pwin_k=['ecutwfc','ibrav']
fh.write(' &SYSTEM\n')
if p['use_symmetry'] :
# Need to use symmetry properly
# create a dummy atoms object for primitive cell
primcell=write_cell_params(fh,a,p)
cr=Atoms(cell=primcell[0],scaled_positions=primcell[1],numbers=primcell[2],pbc=True)
else :
cr=a
fh.write(" nat = %d\n" % (cr.get_number_of_atoms()))
fh.write(" ntyp = %d\n" % (len(set(cr.get_atomic_numbers()))))
pwin_k=['ecutwfc','ibrav']
write_section_params(fh, pwin_k, p)
fh.write(" nat = %d\n" % (a.get_number_of_atoms()))
fh.write(" ntyp = %d\n" % (len(set(a.get_atomic_numbers()))))
fh.write(' /\n')

# ----------------------------------------------------------
# | ELECTRONS section
# ELECTRONS section
# ----------------------------------------------------------

fh.write(' &ELECTRONS\n')
fh.write(' /\n')


# ----------------------------------------------------------
# | Card: ATOMIC_SPECIES
# Card: ATOMIC_SPECIES
# ----------------------------------------------------------

fh.write('ATOMIC_SPECIES\n')

xc=p['xc']
pp_type=p['pp_type']
pp_format=p['pp_format']
for nm, mass in set(zip(a.get_chemical_symbols(),a.get_masses())):
for nm, mass in set(zip(cr.get_chemical_symbols(),cr.get_masses())):
fh.write(" %s %g %s_%s_%s.%s \n" % (nm, mass, nm, xc, pp_type, pp_format))

# ----------------------------------------------------------
# | Card: ATOMIC_POSITIONS
# Card: ATOMIC_POSITIONS
# ----------------------------------------------------------

fh.write('ATOMIC_POSITIONS {crystal}\n')
for n,v in zip(a.get_chemical_symbols(),a.get_scaled_positions()):
fh.write('ATOMIC_POSITIONS crystal\n')
# Now we can write it out
for n,v in zip(cr.get_chemical_symbols(),cr.get_scaled_positions()):
fh.write(" %s %g %g %g\n" % (n, v[0], v[1], v[2]))

# ----------------------------------------------------------
# | Card: CELL_PARAMETERS
# Card: CELL_PARAMETERS
# ----------------------------------------------------------

fh.write('CELL_PARAMETERS {angstrom}\n')
fh.write('CELL_PARAMETERS angstrom\n')

for v in a.get_cell():
for v in cr.get_cell():
fh.write(' %f %f %f\n' % tuple(v))

# ----------------------------------------------------------
# Card: K_POINTS
# ----------------------------------------------------------

fh.write('K_POINTS %s\n' % p['kpt_type'])
if p['kpt_type'] is 'automatic':
fh.write(' %d %d %d %d %d %d\n' % (tuple(p['kpts'])+tuple(p['kpt_shift'])))
elif not p['kpt_type'] is 'gamma':
fh.write(' %d\n' % len(p['kpts']))
for v in p['kpts']:
fh.write(' %.14f %.14f %.14f %.14f\n' % tuple(v))

fh.close()


def make_calc_dir(prefix, bdir='./'):
Expand Down

0 comments on commit a006ace

Please sign in to comment.