Skip to content

Commit

Permalink
Add Bader analysis.
Browse files Browse the repository at this point in the history
Former-commit-id: 30dd1d1c5aa5dd1a7070da41bc2adb9bdb927251 [formerly 0f0f4f3]
Former-commit-id: b7e11f702b83a9b020dff8fec20d35d590ebaaa5
  • Loading branch information
Shyue Ping Ong committed Apr 5, 2013
1 parent 99a3b57 commit 11d14af
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 1 deletion.
2 changes: 1 addition & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ test:
- mv pymatgen pmg
- nosetests:
environment:
PATH: $PATH:`pwd`/cmd_line/enum/Linux_64bit
PATH: $PATH:`pwd`/cmd_line/enum/Linux_64bit:`pwd`/cmd_line/bader/Linux_64bit
Binary file added cmd_line/bader/Darwin_64bit/bader
Binary file not shown.
Binary file added cmd_line/bader/Linux_64bit/bader
Binary file not shown.
110 changes: 110 additions & 0 deletions pymatgen/command_line/bader_caller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python

"""
This module implements an interface to the Henkelmann et al.'s excellent
Fortran code for calculating a Bader charge analysis.
This module depends on a compiled bader executable available in the path.
Please download the library at http://theory.cm.utexas.edu/vasp/bader/ and
follow the instructions to compile the executable.
If you use this module, please cite the following:
G. Henkelman, A. Arnaldsson, and H. Jonsson, "A fast and robust algorithm for
Bader decomposition of charge density", Comput. Mater. Sci. 36, 254-360 (2006).
"""

from __future__ import division

__author__ = "shyuepingong"
__version__ = "0.1"
__maintainer__ = "Shyue Ping Ong"
__email__ = "[email protected]"
__status__ = "Beta"
__date__ = "4/5/13"

import os
import subprocess
import tempfile
import shutil


class BaderAnalysis(object):
"""
Bader analysis for a CHGCAR.
.. attribute: data
Atomic data parsed from bader analysis. Essentially a list of dicts
of the form::
[
{
"dist": 8.769,
"min": 0.8753,
"charge": 7.4168,
"y": 1.1598,
"x": 0.0079,
"z": 0.8348
},
...
]
.. attribute: vacuum_volume
Vacuum volume of the Bader analysis.
.. attribute: vacuum_charge
Vacuum charge of the Bader analysis.
.. attribute: nelectrons
Number of electrons of the Bader analysis.
"""

def __init__(self, filename):
"""
Args:
filename:
The filename of the CHGCAR.
"""
temp_dir = tempfile.mkdtemp()
try:
shutil.copy(filename, os.path.join(temp_dir, "CHGCAR"))
current_dir = os.getcwd()
os.chdir(temp_dir)
rs = subprocess.Popen(["bader", "-p", "atom_index", "-p", "all_atom",
"CHGCAR"],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE, close_fds=True)
rs.communicate()
data = []
with open("ACF.dat") as f:
raw = f.readlines()
headers = [s.lower() for s in raw.pop(0).split()]
raw.pop(0)
while True:
l = raw.pop(0).strip()
if l.startswith("-"):
break
vals = map(float, l.split()[1:])
data.append(dict(zip(headers[1:], vals)))
for l in raw:
toks = l.strip().split(":")
if toks[0] == "VACUUM CHARGE":
self.vacuum_charge = float(toks[1])
elif toks[0] == "VACUUM VOLUME":
self.vacuum_volume = float(toks[1])
elif toks[0] == "NUMBER OF ELECTRONS":
self.nelectrons = float(toks[1])
self.data = data
os.chdir(current_dir)
except Exception as ex:
print str(ex)
finally:
shutil.rmtree(temp_dir)


if __name__ == "__main__":
a = BaderAnalysis("../../test_files/CHGCAR.noncubic")
43 changes: 43 additions & 0 deletions pymatgen/command_line/tests/test_bader_caller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python

"""
TODO: Change the module doc.
"""

from __future__ import division

__author__ = "Shyue Ping Ong"
__copyright__ = "Copyright 2012, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Shyue Ping Ong"
__email__ = "[email protected]"
__date__ = "Jul 22, 2012"

import unittest
import os

from nose.exc import SkipTest

from pymatgen.command_line.bader_caller import BaderAnalysis
from pymatgen.util.io_utils import which


bader_present = which('bader')


class BaderAnalysisTest(unittest.TestCase):

def test_init(self):
if not bader_present:
raise SkipTest("bader executable not present. Skipping...")
test_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..",
'test_files')
analysis = BaderAnalysis(os.path.join(test_dir, "CHGCAR.noncubic"))
self.assertEqual(len(analysis.data), 8)
self.assertAlmostEqual(analysis.data[0]["charge"], 7.4168)
self.assertAlmostEqual(analysis.nelectrons, 52)
self.assertAlmostEqual(analysis.vacuum_charge, 0)


if __name__ == '__main__':
unittest.main()

0 comments on commit 11d14af

Please sign in to comment.