Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Dielectric 5.4.4 (#946)
* Bug fix for NPT DiffusionAnalyzer

The DiffusionAnalyzer from_structures method calculates the
Cartesian displacements using

    c_disp = [np.dot(d, m) for d, m in zip(f_disp, l)]

f_disp has dimensions [site, time step, axis]
l has dimensions [time step, axis, axis]

this means the lattice used for calculating the Cartesian
displacements is selected based on site number, not on time step.

Displacements calculated for NPT simulations therefore contained
errors (equivalent to assuming NVT, and then taking a different
lattice for each site).

This commit fixes this, by replacing the calculation of c_disp
with

    c_disp = []
    for i in f_disp:
        c_disp.append([np.dot(d, m) for d, m in zip(i, l[1:])])

The new calculation also addresses an off-by-one error, where the
displacement at time step t was calculated using the lattice at
time step t-1.

* Alternate dielectric function parsing: vasp 5.4.4

VASP 5.4.4 calculates the frequency dependent dielectric response in two ways, using a "density-density" response function, and using a "velocity-velocity" response function (see the comments in linear_optics.F in the vasp source code). The latter is marked in OUTCAR as current-current (2nd set in vasprun.xml), but is not labelled in vasprun.xml.

This commit addresses an issue where the second unlabelled dielectric function would overwrite the first.

#940

For consistency with older versions of vasp, the "density-density" linear response function
is read into self.dielectric.
The "velocity-velocity" linear response function (described as "current-current" in OUTCAR)
is read into self.other_dielectric['current-current'].

This commit includes a test that if vasprun.xml contains a second unlabelled set of dielectric
repsonse data, this is read into self.other_dielectric['current-current'].

If a third unlablled set of dielectric data is present in the vasprun.xml, a NotImplementedError
is raise (also tested).

* Reimplemented dielectric function parser

Update to pull request #946

The first unlabelled dielectric function data in vasprun.xml is read into
self.dielectric_data['density']. If there is a second unlabelled dielectric
function data set, this is read into self.dielectric_data['velocity'].

self.dielectric now maps to self.dielectric_data['density'] for consistency
with previous behaviour under old VASP versions.
  • Loading branch information
bjmorgan authored and shyuep committed Dec 14, 2017
1 parent 937be1c commit e52597c
Show file tree
Hide file tree
Showing 4 changed files with 25,443 additions and 2 deletions.
14 changes: 12 additions & 2 deletions pymatgen/io/vasp/outputs.py
Expand Up @@ -399,6 +399,7 @@ def _parse(self, stream, parse_dos, parse_eigen, parse_projected_eigen):
self.efermi = None
self.eigenvalues = None
self.projected_eigenvalues = None
self.dielectric_data = {}
self.other_dielectric = {}
ionic_steps = []
parsed_header = False
Expand Down Expand Up @@ -445,8 +446,13 @@ def _parse(self, stream, parse_dos, parse_eigen, parse_projected_eigen):
elem)
elif tag == "dielectricfunction":
if ("comment" not in elem.attrib) or \
elem.attrib["comment"] == "INVERSE MACROSCOPIC DIELECTRIC TENSOR (including local field effects in RPA (Hartree))":
self.dielectric = self._parse_diel(elem)
elem.attrib["comment"] == "INVERSE MACROSCOPIC DIELECTRIC TENSOR (including local field effects in RPA (Hartree))":
if not 'density' in self.dielectric_data:
self.dielectric_data['density'] = self._parse_diel(elem)
elif not 'velocity' in self.dielectric_data:
self.dielectric_data['velocity'] = self._parse_diel(elem)
else:
raise NotImplementedError('This vasprun.xml has >2 unlabelled dielectric functions')
else:
comment = elem.attrib["comment"]
self.other_dielectric[comment] = self._parse_diel(elem)
Expand Down Expand Up @@ -503,6 +509,10 @@ def epsilon_ionic(self):
"""
return self.ionic_steps[-1].get("epsilon_ion", [])

@property
def dielectric(self):
return self.dielectric_data['density']

@property
def lattice(self):
return self.final_structure.lattice
Expand Down
17 changes: 17 additions & 0 deletions pymatgen/io/vasp/tests/test_outputs.py
Expand Up @@ -43,6 +43,23 @@ def test_multiple_dielectric(self):
v = Vasprun(os.path.join(test_dir, "vasprun.GW0.xml"))
self.assertEqual(len(v.other_dielectric), 3)

def test_charge_charge_dielectric(self):
"""
VASP 5.4.4 writes out two dielectric functions to vasprun.xml
These are the "density-density" and "velocity-velocity" linear response functions.
See the comments in `linear_optics.F` for details.
"""
v = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric_5.4.4"),
parse_potcar_file=False)
self.assertEqual( v.dielectric is not None, True )
self.assertEqual( 'density' in v.dielectric_data, True )
self.assertEqual( 'velocity' in v.dielectric_data, True )

def test_vasprun_with_more_than_two_unlabelled_dielectric_functions(self):
with self.assertRaises(NotImplementedError):
Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric_bad"),
parse_potcar_file=False)

def test_bad_vasprun(self):
self.assertRaises(ET.ParseError,
Vasprun, os.path.join(test_dir, "bad_vasprun.xml"))
Expand Down

0 comments on commit e52597c

Please sign in to comment.