Source code for pymatgen.analysis.diffusion.neb.io
# Copyright (c) Materials Virtual Lab.
# Distributed under the terms of the BSD License.
"""Generate input fields for NEB calculations."""
from __future__ import annotations
import copy
from pymatgen.core import Structure
from pymatgen.io.vasp.sets import MITNEBSet, MITRelaxSet
__author__ = "Austen"
[docs]
class MVLCINEBEndPointSet(MITRelaxSet):
"""Class for writing NEB end points relaxation inputs."""
def __init__(self, structure, **kwargs):
r"""
Args:
structure: Structure
**kwargs: Keyword args supported by VaspInputSets.
"""
user_incar_settings = kwargs.get("user_incar_settings", {})
defaults = {
"ISIF": 2,
"EDIFF": 5e-5,
"EDIFFG": -0.02,
"ISMEAR": 0,
"ISYM": 0,
"LCHARG": False,
"LDAU": False,
"NELMIN": 4,
}
if user_incar_settings != {}:
defaults.update(user_incar_settings)
kwargs["user_incar_settings"] = defaults
super().__init__(structure, **kwargs)
[docs]
class MVLCINEBSet(MITNEBSet):
"""
MAVRL-tested settings for CI-NEB calculations. Note that these parameters
requires the VTST modification of VASP from the Henkelman group. See
http://theory.cm.utexas.edu/vtsttools/.
"""
def __init__(self, structures, **kwargs):
r"""
Args:
structures: Input structures.
**kwargs: Keyword args supported by VaspInputSets.
"""
user_incar_settings = kwargs.get("user_incar_settings", {})
# CI-NEB settings
defaults = {
"EDIFF": 5e-5,
"EDIFFG": -0.02,
"IBRION": 3,
"ICHAIN": 0,
"IOPT": 1,
"ISIF": 2,
"ISMEAR": 0,
"ISPIN": 2,
"LCHARG": False,
"LCLIMB": True,
"LDAU": False,
"LORBIT": 0,
"NSW": 200,
"POTIM": 0,
"SPRING": -5,
}
if user_incar_settings != {}:
defaults.update(user_incar_settings)
kwargs["user_incar_settings"] = defaults
super().__init__(structures, **kwargs)
[docs]
def get_endpoints_from_index(structure, site_indices):
"""
This class reads in one perfect structure and the two endpoint structures
are generated using site_indices.
Args:
structure (Structure): A perfect structure.
site_indices (list of int): a two-element list indicating site indices.
Returns:
endpoints (list of Structure): a two-element list of two endpoints
Structure object.
"""
if len(site_indices) != 2 or len(set(site_indices)) != 2:
raise ValueError("Invalid indices!")
if structure[site_indices[0]].specie != structure[site_indices[1]].specie:
raise ValueError("The site indices must be associated with identical species!")
s = structure.copy()
sites = s.sites
# Move hopping atoms to the beginning of species index.
init_site = sites[site_indices[0]]
final_site = sites[site_indices[1]]
sites.remove(init_site)
sites.remove(final_site)
init_sites = copy.deepcopy(sites)
final_sites = copy.deepcopy(sites)
init_sites.insert(0, final_site)
final_sites.insert(0, init_site)
s_0 = Structure.from_sites(init_sites)
s_1 = Structure.from_sites(final_sites)
return [s_0, s_1]
[docs]
def get_endpoint_dist(ep_0, ep_1):
"""
Calculate a list of site distances between two endpoints, assuming periodic
boundary conditions.
Args:
ep_0 (Structure): the first endpoint structure.
ep_1 (Structure): the second endpoint structure.
Returns:
dist (list): a list of distances between two structures.
"""
ep_0.remove_oxidation_states()
ep_1.remove_oxidation_states()
assert ep_0.species == ep_1.species, "Formula mismatch!"
assert ep_0.lattice.abc == ep_0.lattice.abc, "Lattice mismatch!"
distances = []
for site0, site1 in zip(ep_0, ep_1):
fc = (site0.frac_coords, site1.frac_coords)
d = ep_0.lattice.get_distance_and_image(fc[0], fc[1])[0]
distances.append(d)
return distances