Git Product home page Git Product logo

vasp's Introduction

A new ASE interface to Vasp

Update: May 20, 2022. I am going to archive this repo. I don’t think this code works with current versions of ASE, and we aren’t actively using or supporting it. You can still fork the repo, and if someone feels strongly about maintaining it, I am happy to pass the baton. My sense is that the era when it made sense to run Vasp this way has passed though, and a new design is warranted.

Why?

To make it compliant with the FileIOCalculator in ase, and hopefully simplify it.

Goals

  1. Provide an interface that allows all vasp INCAR tags without further modification, i.e. they are mostly just kwargs to the calculator.
  2. Eliminate need for long lists of supported keywords.
  3. Provide an interface that can be extended to allow validation, and user-defined special keywords.
  4. Better treatment of the xc keyword to make it easier to use different functionals.
  5. Smart restarts. We don’t want to run unnecessary calculations if they are already done. We want one script that runs calculations and does analysis.

Installation

Clone this repo somewhere. Add it to your PYTHONPATH and PATH. Set VASP_PP_PATH to point to the directory containing your POTCARs.

export PYTHONPATH=~/kitchin-python/vasp:$PYTHONPATH
export PATH=~/kitchin-python/vasp/bin:$PATH

export VASP_PP_PATH=/opt/kitchingroup/vasp-5.3.5

These directories should contain your POTCARs.

ls -d $VASP_PP_PATH/potpaw_???

Differences from ase.calculators.vasp

Most things are the same. Here are few differences.

label is a directory and the first argument

“label” is the first argument to the calculator, and it specifies the directory where the results are. Almost all file-io is done by path, so few directory changes ever occur.

perpetual restart mode

Always starts in “restart” mode. On initialization the calculator always updates from the file system first, including updating the atoms, then from arguments. This allows you to write one script to setup, run and perform analysis.

special setup syntax

Special setups are now specified by a list of [atom_symbol, potcar_suffix]

In this example we use the potpaw_PBE/O_s/POTCAR.

calc = Vasp('molecules/O_s',
          encut=300,
            xc='PBE',
            ispin=2,
            ismear=0,
            sigma=0.001,
            setups=[['O', '_s']], # specifies O_s potential
            atoms=atoms)

This was changed to help make resorting simpler and reliable.

new rwigs syntax

rwigs is now a dictionary of {atom-symbol: radius}. This makes it easier to correctly generate the INCAR.

ADOS is part of Vasp

The syntax to get the ‘s’ orbital on the 0-indexed atom is:

energies, c_s = calc.get_ados(0, 's')

Only ‘s’, ‘p’, and ‘d’ are currently supported.

Integrated visualization

This will show you the trajectory of the geometry relaxation.

from vasp import Vasp
calc = Vasp('molecules/h2o-relax-centered')
calc.view()

New default parameters

These may change. We don’t usually write out the charge and wavecar files because they are large. An exception is if nsw>0, then we do write out the wavecar file to facilitate restarts.

from vasp import Vasp
print(Vasp.default_parameters)

Automatic job submission and job management.

Calculations are automatically submitted to a queue system with well-defined exceptions to provide job management. The setup is somewhat general, and must be tuned for specific clusters.

Built-in exception handling.

All functions are wrapped in exception handling code to make some things easy to handle.

“Smart” kwarg expansion.

Some kwargs are special, e.g. you can set ispin=2 and the calculator will automatically set the magmom key from the atoms object.

Native support for the ase-db.

We actually use the ase-db to store calculation information.

from vasp import Vasp
from ase.db import connect

bond_lengths = [1.05, 1.1, 1.15, 1.2, 1.25]
calcs = [Vasp('molecules/co-{0}'.format(d)) for d in bond_lengths]

con = connect('co-database.db', append=False)
for atoms in [calc.get_atoms() for calc in calcs]:
    con.write(atoms)

Validation of some kwargs.

The vasp.validate file defines validation functions for many keywords, as well as brief documentation for them. This is integrated with Emacs to provide tooltips and easy access to documentation while working.

VASPRC

This is a configuration file that allows customization of how jobs are submitted and whether validation is performed.

Examples of usage

A simple CO calculation

This is the prototypical simple calculation.

from ase import Atoms, Atom
from vasp import Vasp
from vasp.vasprc import VASPRC
VASPRC['mode'] = 'run'

co = Atoms([Atom('C', [0, 0, 0]),
            Atom('O', [1.2, 0, 0])],
           cell=(6., 6., 6.))

calc = Vasp('~/dft-book-new-vasp/molecules/simple-co',  # output dir
            xc='pbe',    # the exchange-correlation functional
            nbands=6,    # number of bands
            encut=350,   # planewave cutoff
            ismear=1,    # Methfessel-Paxton smearing
            sigma=0.01,  # very small smearing factor for a molecule
            atoms=co)

print('energy = {0} eV'.format(co.get_potential_energy()))
print(co.get_forces())

A functional approach to calculations

Here we use list comprehensions to calculate the energy as a function of bond lengths.

from vasp import Vasp
from ase import Atom, Atoms
import logging

bond_lengths = [1.05, 1.1, 1.15, 1.2, 1.25]

ATOMS = [Atoms([Atom('C', [0, 0, 0]),
                Atom('O', [d, 0, 0])],
               cell=(6, 6, 6))
         for d in bond_lengths]

calcs = [Vasp('~/dft-book-new-vasp/molecules/co-{0}'.format(d),  # output dir
                xc='PBE',
                nbands=6,
                encut=350,
                ismear=1,
                sigma=0.01, debug=True,
                atoms=atoms)
         for d, atoms in zip(bond_lengths, ATOMS)]

energies = [atoms.get_potential_energy() for atoms in ATOMS]

print(energies)

tpptree

[-14.21584765, -14.72174343, -14.84115208, -14.69111507, -14.35508371]

Some new ideas in job management

By default, many exceptions are handled automatically, and if calculations are not finished the quantities are returned as None. This leads to some challenges if you want to do analysis before the results are ready.

Our workflow relies on asynchronously running jobs in a queue. To avoid blocking scripts, we setup everything so that scripts just exit if they cannot continue, and we rerun them later.

We provide the following tools for handling these situations.

calc.abort()

The abort function simply exits the program when called.

from vasp import Vasp
from ase.lattice.cubic import BodyCenteredCubic

atoms = BodyCenteredCubic(directions=[[1, 0, 0],
                                      [0, 1, 0],
                                      [0, 0, 1]],
                                      size=(1, 1, 1),
                                      symbol='Fe')

NUPDOWNS = [0.0, 2.0, 4.0, 5.0, 6.0, 8.0]
energies = []
for B in NUPDOWNS:
    calc = Vasp('bulk/Fe-bcc-fixedmagmom-{0:1.2f}'.format(B),
                xc='PBE',
                encut=300,
                kpts=(4, 4, 4),
                ispin=2,
                nupdown=B,
                atoms=atoms)
    energies.append(atoms.get_potential_energy())

if None in energies:
    calc.abort()

# some analysis that depends on all energies being present

calc.wait()

The wait function does not actually wait. It does try to get the energy and run the job, and if it is not ready, it exits. The name or action of this function may change.

from vasp import Vasp
from ase.lattice.cubic import FaceCenteredCubic

atoms = FaceCenteredCubic(symbol='Al')

calc = Vasp('bulk/Al-bulk',
            xc='PBE',
            kpts=(12, 12, 12),
            encut=350,
            prec='High',
            isif=3,
            nsw=30,
            ibrion=1,
            atoms=atoms)
calc.wait()

# some analysis that depends on the calculation being done

calc.stop_if(condition)

Sometimes you would like some condition to determine if you stop. This is a one line version of the if statement combined with calc.abort()

from vasp import Vasp
from ase import Atom, Atoms
import numpy as np
# fcc
LC = [3.5, 3.55, 3.6, 3.65, 3.7, 3.75]
volumes, energies = [], []
for a in LC:
    atoms = Atoms([Atom('Ni', (0, 0, 0), magmom=2.5)],
                  cell=0.5 * a * np.array([[1.0, 1.0, 0.0],
                                           [0.0, 1.0, 1.0],
                                           [1.0, 0.0, 1.0]]))

    calc = Vasp('bulk/Ni-{0}'.format(a),
                xc='PBE',
                encut=350,
                kpts=(12, 12, 12),
                ispin=2,
                atoms=atoms)
    energies.append(calc.potential_energy)
    volumes.append(atoms.get_volume())

calc.stop_if(None in energies)

# some analysis requireing all the energies.

Run simulations with a Lisp

One of my motivations for the rewrite was to enable me to use Hy (http://docs.hylang.org/en/latest/) in these simulations. Hy is a Lisp that runs Python. Here is an example calculation. This might be interesting because it allows you to write macros. I am not sure what I will do that yet, but I look forward to trying it out.

(import [ase [Atom Atoms]])
(import [vasp [Vasp]])

(setv co (Atoms [(Atom "C" [0.0 0.0 0.0])
                 (Atom "O" [1.2 0.0 0.0])]
                :cell [6.0 6.0 6.0]))

(setv calc (Vasp "~/dft-book-new-vasp/molecules/simple-co-hy"
                 :xc "pbe"
                 :nbands 6
                 :encut 350
                 :ismear 1
                 :sigma 0.01
                 :atoms co))

(print (.format "energy = {0} eV"
                (.get_potential_energy co)))

(print calc.potential_energy)
(print (.get_forces co))

vaspsum

This command line utility provides a variety of ways to summarize a calculation. For example, you can use this to print the input files:

vaspsum --vasp ~/dft-book-new-vasp/molecules/simple-co

Or this to output the ase-db json.

vaspsum --json ~/dft-book-new-vasp/molecules/simple-co

vaspy-mode

We provide vaspy-mode to enhance using vasp in Emacs. The main feature it provides is syntax highlighting on vasp keywords with a tooltip on them showing the first line of the validation docstring, and making them clickable to show the whole docstring.

Add this to your Emacs initialization file (obviously change the path to where you installed the vasp module.

(add-to-list 'load-path "~/kitchin-python/vasp")
(require 'vaspy-mode)

Create a Vasp calculator.

label: the directory where the calculation files will be and the calculation run.

debug: an integer, but usually something like logging.DEBUG

exception_handler: A function for handling exceptions. The function should take the arguments returned by sys.exc_info(), which is the exception type, value and traceback. The default is VaspExceptionHandler.

**kwargs Any Vasp keyword can be used, e.g. encut=450.

The tag will be upcased when written, and the value is written depending on its type. E.g. integers, floats and strings are written as they are. True/False is written as .TRUE. and .FALSE. and Python lists/tuples are written as space delimited lists.

Special kwargs:

xc: string indicating the functional to use. It is expanded from Vasp.xc_defaults to the relevant Vasp tags.

kpts: Usually a 3 element list of [k1, k2, k3], but may also be a list of kpts.

setups: This describes special setups for the POTCARS. It is a list of the following items.

(atom_index, suffix) for exampe: (2, ‘_sv’)

(atom_symbol, suffix) for example (‘Zr’, ‘_sv’)

If (atom_index, suffix) is used then only that atom index will have a POTCAR defined by ‘{}{}’.format(atoms[atom_index].symbol, suffix)

If (atom_symbol, suffix) is used then atoms with that symbol (except any identified by (atom_index, suffix) will use a POTCAR defined by ‘{}{}’.format(atom_symbol, suffix)

This syntax has changed from the old dictionary format. The reason for this is that this sorting must be deterministic. Getting keys in a dictionary is not deterministic.

ldau_luj: This is a dictionary to set the DFT+U tags. For example, to put U=4 on the d-orbitals (L=2) of Cu, and nothing on the oxygen atoms in a calculation use:

ldau_luj={‘Cu’:{‘L’:2, ‘U’:4.0, ‘J’:0.0}, ‘O’:{‘L’:-1, ‘U’:0.0, ‘J’:0.0}},

./vasp/vasp_core.py::137

def __init__(self, label,
             restart=True, ignore_bad_restart_file=False,
             atoms=None, scratch=None,
             debug=None,
             exception_handler=VaspExceptionHandler,
             **kwargs):
    """Create a Vasp calculator.

    label: the directory where the calculation files will be and
    the calculation run.

    debug: an integer, but usually something like logging.DEBUG

    exception_handler: A function for
    handling exceptions. The function should take the arguments
    returned by sys.exc_info(), which is the exception type, value
    and traceback. The default is VaspExceptionHandler.

    **kwargs
      Any Vasp keyword can be used, e.g. encut=450.

      The tag will be upcased when written, and the value is
      written depending on its type. E.g. integers, floats and
      strings are written as they are. True/False is written as
      .TRUE. and .FALSE. and Python lists/tuples are written as
      space delimited lists.

    Special kwargs:

    xc: string indicating the functional to use. It is expanded
    from Vasp.xc_defaults to the relevant Vasp tags.

    kpts: Usually a 3 element list of [k1, k2, k3], but may also
    be a list of kpts.

    setups: This describes special setups for the POTCARS. It is a list of
      the following items.

      (atom_index, suffix)   for exampe: (2, '_sv')

      (atom_symbol, suffix)  for example ('Zr', '_sv')

      If (atom_index, suffix) is used then only that atom index will have a
      POTCAR defined by '{}{}'.format(atoms[atom_index].symbol, suffix)

      If (atom_symbol, suffix) is used then atoms with that symbol (except
      any identified by (atom_index, suffix) will use a POTCAR defined by
      '{}{}'.format(atom_symbol, suffix)

      This syntax has changed from the old dictionary format. The
      reason for this is that this sorting must be
      deterministic. Getting keys in a dictionary is not
      deterministic.

    ldau_luj: This is a dictionary to set the DFT+U tags. For
    example, to put U=4 on the d-orbitals (L=2) of Cu, and nothing
    on the oxygen atoms in a calculation use:

        ldau_luj={'Cu':{'L':2,  'U':4.0, 'J':0.0},
                  'O':{'L':-1, 'U':0.0, 'J':0.0}},

    """
    # set first so self.directory is right
    # cast as str in case label is unicode, i.e. if it is from hy.
    self.set_label(label)
    self.debug = debug
    self.exception_handler = exception_handler

    self.neb = None
    # We have to check for the type here this because an NEB uses
    # a list of atoms objects. We set pbc to be True because that
    # is what is read in from files, and if we don't the atoms
    # look incompatible.
    if atoms is not None and isinstance(atoms, ase.atoms.Atoms):
        atoms.pbc = [True, True, True]
    elif atoms is not None:
        for a in atoms:
            a.pbs = [True, True, True]
        self.neb = True

    # We do not pass kwargs here. Some of the special kwargs
    # cannot be set at this point since they need to know about
    # the atoms and parameters. This reads params and results from
    # existing files if they are there. It calls self.read(). It
    # should update the atoms from what is on file.

    if self.neb is not None:
        FileIOCalculator.__init__(self, restart, ignore_bad_restart_file,
                                  str(label))
        self.neb = atoms
    else:
        FileIOCalculator.__init__(self, restart, ignore_bad_restart_file,
                                  str(label), atoms)

    # The calculator should be up to date with the file
    # system here.

    # Add default parameters if they aren't set otherwise.
    for key, val in Vasp.default_parameters.iteritems():
        if key not in kwargs and key not in self.parameters:
            kwargs[key] = val

    # Next we update kwargs with the special kwarg
    # dictionaries. ispin, rwigs are special, and needs sorted
    # atoms. so we save it for later.
    if 'ispin' in kwargs:
        ispin = kwargs['ispin']
        del kwargs['ispin']
    else:
        ispin = None

    if 'rwigs' in kwargs:
        rwigs = kwargs['rwigs']
        del kwargs['rwigs']
    else:
        rwigs = None

    # Now update the parameters. If there are any new kwargs here,
    # it will reset the calculator and cause a calculation to be
    # run if needed.
    self.set(**kwargs)

    # In case no atoms was on file, and one is passed in, we set
    # it here.
    if self.atoms is None and atoms is not None and self.neb is None:
        self.sort_atoms(atoms)
    elif self.neb is not None:
        self.sort_atoms(self.neb[0])

    # These depend on having atoms already.
    if ispin is not None:
        self.set(**self.set_ispin_dict(ispin))

    if rwigs is not None:
        self.set(**self.set_rwigs_dict(rwigs))

    # Finally run validate functions
    if VASPRC['validate']:
        for key, val in self.parameters.iteritems():
            if key in validate.__dict__:
                f = validate.__dict__[key]
                f(self, val)
            else:
                warnings.warn('No validation for {}'.format(key))

Vasp.__str__

args = (self)

Pretty representation of a calculation.

TODO: make more like jaspsum.

./vasp/vasp_core.py::361

def __str__(self):
    """Pretty representation of a calculation.

    TODO: make more like jaspsum.

    """
    s = ['']
    s += ['Vasp calculation in {self.directory}\n']
    if os.path.exists(self.incar):
        with open(self.incar) as f:
            s += [f.read()]
    else:
        s += ['No INCAR yet']

    if os.path.exists(self.poscar):
        with open(self.poscar) as f:
            s += [f.read()]
    else:
        s += ['No POSCAR yet']

    return '\n'.join(s).format(self=self)

Vasp.abort

args = (self)

Abort and exit the program the calculator is running in.

./vasp/vasp_core.py::548

def abort(self):
    """Abort and exit the program the calculator is running in."""
    import sys
    sys.exit()

Vasp.attach_charges

args = (self, fileobj=None, displacement=0.0001)

Attach the charges from the fileobj to the atoms on the calculator.

This is a modified version of the attach_charges function in ase.io.bader to work better with VASP. Does not require the atom positions to be in Bohr and references the charge to the ZVAL in the POTCAR

Monkey-patch defined in vasp/bader.py at line 9

./vasp/bader.py::9

@monkeypatch_class(vasp.Vasp)
def attach_charges(self, fileobj=None, displacement=1e-4):
    """Attach the charges from the fileobj to the atoms on the calculator.

    This is a modified version of the attach_charges function in
    ase.io.bader to work better with VASP.
    Does not require the atom positions to be in Bohr and references
    the charge to the ZVAL in the POTCAR
    """
    if fileobj is None:
        fileobj = os.path.join(self.directory, 'ACF.dat')

    if isinstance(fileobj, str):
        fileobj = open(fileobj)
        f_open = True

    # First get a dictionary of ZVALS from the pseudopotentials
    LOP = self.get_pseudopotentials()
    ppp = os.environ['VASP_PP_PATH']

    zval = {}
    for sym, ppath, hash in LOP:
        fullpath = os.path.join(ppp, ppath)
        z = get_ZVAL(fullpath)
        zval[sym] = z

    atoms = self.atoms
    # Get sorted symbols and positions according to POSCAR and ACF.dat
    symbols = np.array(atoms.get_chemical_symbols())[self.resort]
    positions = atoms.get_positions()[self.resort]

    charges = []
    sep = '---------------'
    i = 0  # Counter for the lines
    k = 0  # Counter of sep
    assume6columns = False
    for line in fileobj:
        if line[0] == '\n':  # check if there is an empty line in the
            i -= 1           # head of ACF.dat file
        if i == 0:
            headings = line
            if 'BADER' in headings.split():
                j = headings.split().index('BADER')
            elif 'CHARGE' in headings.split():
                j = headings.split().index('CHARGE')
            else:
                print('Can\'t find keyword "BADER" or "CHARGE".'
                      ' Assuming the ACF.dat file has 6 columns.')
                j = 4
                assume6columns = True
        if sep in line:  # Stop at last seperator line
            if k == 1:
                break
            k += 1
        if not i > 1:
            pass
        else:
            words = line.split()
            if assume6columns is True:
                if len(words) != 6:
                    raise IOError('Number of columns in ACF file incorrect!\n'
                                  'Check that Bader program version >= 0.25')

            sym = symbols[int(words[0]) - 1]
            charges.append(zval[sym] - float(words[j]))

            if displacement is not None:
                # check if the atom positions match
                xyz = np.array([float(w) for w in words[1:4]])
                assert (np.linalg.norm(positions[int(words[0]) - 1] - xyz)
                        < displacement)
        i += 1

    if f_open:
        fileobj.close()

    # Now attach the resorted charges to the atom
    charges = np.array(charges)[self.resort]
    for atom in self.atoms:
        atom.charge = charges[atom.index]

Vasp.bader

args = (self, cmd=None, ref=False, verbose=False, overwrite=False)

Performs bader analysis for a calculation. Follows defaults unless full shell command is specified Does not overwrite existing files if overwrite=False If ref = True, tries to reference the charge density to the sum of AECCAR0 and AECCAR2 Requires the bader.pl (and chgsum.pl) script to be in the system PATH

Monkey-patch defined in vasp/bader.py at line 108

./vasp/bader.py::108

@monkeypatch_class(vasp.Vasp)
def bader(self, cmd=None, ref=False, verbose=False, overwrite=False):
    """Performs bader analysis for a calculation.
    Follows defaults unless full shell command is specified
    Does not overwrite existing files if overwrite=False
    If ref = True, tries to reference the charge density to
    the sum of AECCAR0 and AECCAR2
    Requires the bader.pl (and chgsum.pl) script to be in the system PATH
    """
    cwd = os.getcwd()
    try:
        os.chdir(self.directory)

        if 'ACF.dat' in os.listdir(".") and not overwrite:
            self.attach_charges()
            return

        if cmd is None:
            if ref:
                self.chgsum()
                cmdlist = ['bader',
                           'CHGCAR',
                           '-ref',
                           'CHGCAR_sum']
            else:
                cmdlist = ['bader', 'CHGCAR']
        elif type(cmd) is str:
            cmdlist = cmd.split()
        elif type(cmd) is list:
            cmdlist = cmd

        p = Popen(cmdlist, stdin=PIPE, stdout=PIPE, stderr=PIPE)
        out, err = p.communicate()
        if out == '' or err != '':
            raise Exception('Cannot perform Bader:\n\n{0}'.format(err))
        elif verbose:
            print('Bader completed for {0}'.format(self.vaspdir))

        self.attach_charges('ACF.dat')
    finally:
        os.chdir(cwd)

Vasp.calculate

args = (self, atoms=None, properties=[‘energy’], system_changes=None)

Monkey patch to submit job through the queue. If this is called, then the calculator thinks a job should be run. If we are in the queue, we should run it, otherwise, a job should be submitted.

Monkey-patch defined in vasp/runner.py at line 61

./vasp/runner.py::61

@monkeypatch_class(vasp.Vasp)
def calculate(self, atoms=None, properties=['energy'],
              system_changes=None):
    """Monkey patch to submit job through the queue.
    If this is called, then the calculator thinks a job should be run.
    If we are in the queue, we should run it, otherwise, a job should
    be submitted.
    """
    log.debug('In queue: {}'.format(self.in_queue()))
    if self.in_queue():
        raise VaspQueued('{} Queued: {}'.format(self.directory,
                                                self.get_db('jobid')))

    # not in queue. Delete the jobid
    if self.get_db('jobid') is not None:
        self.write_db(jobid=None)

        # we should check for errors here.
        self.read_results()
        return

    if (not self.calculation_required(atoms, ['energy'])
        and not self.check_state()):
        print('No calculation_required.')
        self.read_results()
        return

    # The subclass implementation should first call this
    # implementation to set the atoms attribute.
    Calculator.calculate(self, atoms, properties, system_changes)

    self.write_input(atoms, properties, system_changes)
    if self.parameters.get('luse_vdw', False):
        kernel = os.path.join(self.directory, 'vdw_kernel.bindat')
        if not os.path.exists(kernel):
            os.symlink(VASPRC['vdw_kernel.bindat'], kernel)

    # if we are in the queue and vasp is called or if we want to use
    # mode='run' , we should just run the job. First, we consider how.
    if 'PBS_O_WORKDIR' in os.environ or VASPRC['mode'] == 'run':
        if 'PBS_NODEFILE' in os.environ:
            # we are in the queue. determine if we should run serial
            # or parallel
            NPROCS = len(open(os.environ['PBS_NODEFILE']).readlines())
            log.debug('Found {0} PROCS'.format(NPROCS))
            if NPROCS == 1:
                # no question. running in serial.
                vaspcmd = VASPRC['vasp.executable.serial']
                log.debug('NPROCS = 1. running in serial')
                exitcode = os.system(vaspcmd)
                return exitcode
            else:
                # vanilla MPI run. multiprocessing does not work on more
                # than one node, and you must specify in VASPRC to use it
                if (VASPRC['queue.nodes'] > 1
                    or (VASPRC['queue.nodes'] == 1
                        and VASPRC['queue.ppn'] > 1
                        and (VASPRC['multiprocessing.cores_per_process']
                             == 'None'))):
                    s = 'queue.nodes = {0}'.format(VASPRC['queue.nodes'])
                    log.debug(s)
                    log.debug('queue.ppn = {0}'.format(VASPRC['queue.ppn']))
                    mpc = VASPRC['multiprocessing.cores_per_process']
                    log.debug('multiprocessing.cores_per_process'
                              '= {0}'.format(mpc))
                    log.debug('running vanilla MPI job')

                    log.debug('MPI NPROCS = {}'.format(NPROCS))
                    vaspcmd = VASPRC['vasp.executable.parallel']
                    parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd)
                    exitcode = os.system(parcmd)
                    return exitcode
                else:
                    # we need to run an MPI job on cores_per_process
                    if VASPRC['multiprocessing.cores_per_process'] == 1:
                        log.debug('running single core multiprocessing job')
                        vaspcmd = VASPRC['vasp.executable.serial']
                        exitcode = os.system(vaspcmd)
                    elif VASPRC['multiprocessing.cores_per_process'] > 1:
                        log.debug('running mpi multiprocessing job')
                        NPROCS = VASPRC['multiprocessing.cores_per_process']

                        vaspcmd = VASPRC['vasp.executable.parallel']
                        parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd)
                        exitcode = os.system(parcmd)
                        return exitcode
        else:
            # probably running at cmd line, in serial.
            try:
                cwd = os.getcwd()
                os.chdir(self.directory)
                vaspcmd = VASPRC['vasp.executable.serial']
                status, output, err = getstatusoutput(vaspcmd,
                                                      stdout=subprocess.PIPE,
                                                      stderr=subprocess.PIPE)
                if status == 0:
                    self.read_results()
                    return True
                else:
                    return output
            finally:
                os.chdir(cwd)
        # end

    # if you get here, a job is getting submitted
    CWD = os.getcwd()
    VASPDIR = self.directory
    script = """
#!/bin/bash
cd {CWD}  # this is the current working directory
cd {VASPDIR}  # this is the vasp directory
runvasp.py     # this is the vasp command
#end""".format(**locals())

    jobname = VASPDIR
    log.debug('{0} will be the jobname.'.format(jobname))
    log.debug('-l nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'],
                                            VASPRC['queue.ppn']))

    cmdlist = ['{0}'.format(VASPRC['queue.command'])]
    cmdlist += ['-o', VASPDIR]
    cmdlist += [option for option in VASPRC['queue.options'].split()]
    cmdlist += ['-N', '{0}'.format(jobname),
                '-l walltime={0}'.format(VASPRC['queue.walltime']),
                '-l nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'],
                                              VASPRC['queue.ppn']),
                '-l mem={0}'.format(VASPRC['queue.mem'])]
    log.debug('{0}'.format(' '.join(cmdlist)))
    p = subprocess.Popen(cmdlist,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

    log.debug(script)

    out, err = p.communicate(script)

    if out == '' or err != '':
        raise Exception('something went wrong in qsub:\n\n{0}'.format(err))

    self.write_db(jobid=out.strip())

    raise VaspSubmitted('{} submitted: {}'.format(self.directory,
                                                  out.strip()))

Vasp.calculation_required

args = (self, atoms=None, properties=[‘energy’])

Returns if a calculation is needed.

./vasp/vasp_core.py::491

def calculation_required(self, atoms=None, properties=['energy']):
    """Returns if a calculation is needed."""

    if atoms is None:
        atoms = self.get_atoms()

    system_changes = self.check_state(atoms)
    if system_changes:
        print('Calculation needed for {}'.format(system_changes))
        return True

    for name in properties:
        if name not in self.results:
            print('{} not in {}. Calc required.'.format(name,
                                                            self.results))
            return True

    # if the calculation is finished we do not need to run.
    if os.path.exists(self.outcar):
        with open(self.outcar) as f:
            lines = f.readlines()
            if 'Voluntary context switches:' in lines[-1]:
                return False

Vasp.check_state

args = (self, atoms=None)

Check if any changes exist that require new calculations.

./vasp/vasp_core.py::406

def check_state(self, atoms=None):
    """Check if any changes exist that require new calculations."""
    if atoms is None:
        atoms = self.get_atoms()

    system_changes = FileIOCalculator.check_state(self, atoms)
    # Ignore boundary conditions:
    if 'pbc' in system_changes:
        system_changes.remove('pbc')

    # if dir is empty, there is nothing to read here.
    if self.get_state() == Vasp.EMPTY:
        return system_changes

    # Check if the parameters have changed
    file_params = {}
    file_params.update(self.read_incar())
    file_params.update(self.read_potcar())
    file_params.update(self.read_kpoints())

    xc_keys = sorted(Vasp.xc_defaults,
                     key=lambda k: len(Vasp.xc_defaults[k]),
                     reverse=True)

    for ex in xc_keys:
        pd = {k: file_params.get(k, None)
              for k in Vasp.xc_defaults[ex]}
        if pd == Vasp.xc_defaults[ex]:
            file_params['xc'] = ex.lower()
            break

    # reconstruct ldau_luj if necessary
    if 'ldauu' in file_params:
        ldaul = file_params['ldaul']
        ldauj = file_params['ldauj']
        ldauu = file_params['ldauu']

        with open(self.potcar) as f:
            lines = f.readlines()

        # symbols are in the first line of each potcar
        symbols = [lines[0].split()[1]]
        for i, line in enumerate(lines):
            if 'End of Dataset' in line and i != len(lines) - 1:
                symbols += [lines[i + 1].split()[1]]

        ldau_luj = {}
        for sym, l, j, u in zip(symbols, ldaul, ldauj, ldauu):
            ldau_luj[sym] = {'L': l, 'U': u, 'J': j}

        file_params['ldau_luj'] = ldau_luj

    if not self.parameters == file_params:
        new_keys = set(self.parameters.keys()) - set(file_params.keys())
        missing_keys = (set(file_params.keys()) -
                        set(self.parameters.keys()))
        log.debug('New keys: {}'.format(new_keys))
        log.debug('Missing keys: {}'.format(missing_keys))
        system_changes += ['params_on_file']

    return system_changes

Vasp.chgsum

args = (self)

Uses the chgsum.pl utility to sum over the AECCAR0 and AECCAR2 files.

Monkey-patch defined in vasp/bader.py at line 91

./vasp/bader.py::91

@monkeypatch_class(vasp.Vasp)
def chgsum(self):
    """Uses the chgsum.pl utility to sum over the AECCAR0 and AECCAR2 files."""
    cwd = os.getcwd()
    try:
        os.chdir(self.directory)
        cmdlist = ['chgsum.pl',
                   'AECCAR0',
                   'AECCAR2']
        p = Popen(cmdlist, stdin=PIPE, stdout=PIPE, stderr=PIPE)
        out, err = p.communicate()
        if out == '' or err != '':
            raise Exception('Cannot perform chgsum:\n\n{0}'.format(err))
    finally:
        os.chdir(cwd)

Vasp.clone

args = (self, newdir)

Copy the calculation directory to newdir and set label to newdir.

./vasp/vasp_core.py::567

def clone(self, newdir):
    """Copy the calculation directory to newdir and set label to
    newdir.

    """
    state = self.get_state()

    import shutil
    if not os.path.isdir(newdir):
        shutil.copytree(self.directory, newdir)

        # need some cleanup here. do not copy jobids, etc...
        # What survives depends on the state
        # delete these files if not finished.
        if state in [Vasp.QUEUED, Vasp.NOTFINISHED]:
            os.unlink(os.path.join(newdir, 'OUTCAR'))
            os.unlink(os.path.join(newdir, 'vasprun.xml'))

        if state in [Vasp.EMPTYCONTCAR]:
            os.unlink(os.path.join(newdir, 'OUTCAR'))
            os.unlink(os.path.join(newdir, 'vasprun.xml'))
            os.unlink(os.path.join(newdir, 'CONTCAR'))

    self.__init__(newdir)
    self.write_db(jobid=None, path=newdir)

Vasp.describe

args = (self, long=False)

Describe the parameters used with docstrings in vasp.validate.

./vasp/vasp_core.py::721

def describe(self, long=False):
    """Describe the parameters used with docstrings in vasp.validate."""
    for key in sorted(self.parameters.keys()):
        if key in validate.__dict__:
            f = validate.__dict__[key]
            d = f.__doc__ or 'No docstring found.'
            print('{} = {}:'.format(key, self.parameters[key]))
            if long:
                print('  ' + d)
            else:
                print('  ' + d.split('\n')[0])
            print('')

Vasp.get_ados

args = (self, atom_index, orbital, spin=1, efermi=None)

Return Atom projected DOS for atom index, orbital and spin.

orbital: string [’s’, ‘p’, ‘d’]

If efermi is not None, use this value as 0.0.

Monkey-patch defined in vasp/getters.py at line 182

./vasp/getters.py::182

@monkeypatch_class(vasp.Vasp)
def get_ados(self, atom_index, orbital, spin=1, efermi=None):
    """Return Atom projected DOS for atom index, orbital and spin.

    orbital: string ['s', 'p', 'd']

    If efermi is not None, use this value as 0.0.

    :returns: (energies, ados)

    """
    self.update()

    with open(os.path.join(self.directory,
                           'vasprun.xml')) as f:
        tree = ElementTree.parse(f)

    path = "/".join(['calculation', 'dos',
                     'partial',
                     'array',
                     'set',
                     'set[@comment="ion {}"]',
                     'set[@comment="spin {}"]',
                     "r"])
    path = path.format(self.resort.index(atom_index) + 1, spin)
    log.debug(path)

    results = [[float(x) for x in el.text.split()]
               for el in tree.findall(path)]

    if efermi is None:
        efermi = self.get_fermi_level()
    else:
        efermi = 0.0

    energy = np.array([x[0] for x in results]) - efermi
    ados = np.array([x['spd'.index(orbital) + 1] for x in results])

    return [energy, ados]

Vasp.get_beefens

args = (self, n=-1)

Get the BEEFens 2000 ensemble energies from the OUTCAR. This only works with Vasp 5.3.5 compiled with libbeef. I am pretty sure this array is the deviations from the total energy. There are usually 2000 of these, but it is not clear this will always be the case. I assume the 2000 entries are always in the same order, so you can calculate ensemble energy differences for reactions, as long as the number of samples in the ensemble is the same. There is usually more than one BEEFens section. By default we return the last one. Choose another one with the the :par: n. see http://suncat.slac.stanford.edu/facility/software/functional/

Monkey-patch defined in vasp/getters.py at line 39

./vasp/getters.py::39

@monkeypatch_class(vasp.Vasp)
def get_beefens(self, n=-1):
    """Get the BEEFens 2000 ensemble energies from the OUTCAR.
    This only works with Vasp 5.3.5 compiled with libbeef.
    I am pretty sure this array is the deviations from the total
    energy. There are usually 2000 of these, but it is not clear this will
    always be the case. I assume the 2000 entries are always in the same
    order, so you can calculate ensemble energy differences for reactions,
    as long as the number of samples in the ensemble is the same.
    There is usually more than one BEEFens section. By default we
    return the last one. Choose another one with the the :par: n.
    see http://suncat.slac.stanford.edu/facility/software/functional/
    """
    self.update()
    beefens = []
    with open(os.path.join(self.directory, 'OUTCAR')) as f:
        lines = f.readlines()
        for i, line in enumerate(lines):
            if 'BEEFens' in line:
                nsamples = int(re.search('(\d+)', line).groups()[0])
                beefens.append([float(x) for x in lines[i + 1: i + nsamples]])
    return np.array(beefens[n])

Vasp.get_charge_density

args = (self, spin=0, filename=None)

Returns x, y, and z coordinate and charge density arrays.

Supported file formats: CHG, CHGCAR :param int spin: an integer

Relies on :func:`ase.calculators.vasp.VaspChargeDensity`.

Monkey-patch defined in vasp/getters.py at line 327

./vasp/getters.py::327

@monkeypatch_class(vasp.Vasp)
def get_charge_density(self, spin=0, filename=None):
    """Returns x, y, and z coordinate and charge density arrays.

    Supported file formats: CHG, CHGCAR
    :param int spin: an integer
    :returns: x, y, z, charge density arrays
    :rtype: 3-d numpy arrays
    Relies on :func:`ase.calculators.vasp.VaspChargeDensity`.
    """
    self.update()

    if not self.parameters.get('lcharg', False):
        raise Exception('CHG was not written. Set lcharg=True')

    if filename is None:
        filename = os.path.join(self.directory, 'CHG')

    x, y, z, data = get_volumetric_data(self, filename=filename)
    return x, y, z, data[spin]

Vasp.get_db

args = (self, *keys)

Retrieve values for each key in keys.

First look for key/value, then in data.

Monkey-patch defined in vasp/getters.py at line 12

./vasp/getters.py::12

@monkeypatch_class(vasp.Vasp)
def get_db(self, *keys):
    """Retrieve values for each key in keys.

    First look for key/value, then in data.

    """
    dbfile = os.path.join(self.directory, 'DB.db')

    if not os.path.exists(dbfile):
        return [None for key in keys] if len(keys) > 1 else None

    vals = [None for key in keys]
    from ase.db import connect

    with connect(dbfile) as con:
        try:
            at = con.get(id=1)
            for i, key in enumerate(keys):
                vals[i] = (at.key_value_pairs.get(key, None)
                           or at.data.get(key, None))
        except KeyError, e:
            if e.message == 'no match':
                pass
    return vals if len(vals) > 1 else vals[0]

Vasp.get_default_number_of_electrons

args = (self, filename=None)

Return the default electrons for each species.

Monkey-patch defined in vasp/getters.py at line 243

./vasp/getters.py::243

@monkeypatch_class(vasp.Vasp)
def get_default_number_of_electrons(self, filename=None):
    """Return the default electrons for each species."""
    if filename is None:
        filename = os.path.join(self.directory, 'POTCAR')

    if not os.path.exists(filename):
        self.write_input()

    nelect = []
    lines = open(filename).readlines()
    for n, line in enumerate(lines):
        if line.find('TITEL') != -1:
            symbol = line.split('=')[1].split()[1].split('_')[0].strip()
            valence = float(lines[n + 4].split(';')[1]
                            .split('=')[1].split()[0].strip())
            nelect.append((symbol, valence))
    return nelect

Vasp.get_dipole_moment

args = (self, atoms=None)

Return dipole_moment.

dipole_moment = ((dipole_vector**2).sum())**0.5/Debye

Monkey-patch defined in vasp/getters.py at line 468

./vasp/getters.py::468

@monkeypatch_class(vasp.Vasp)
def get_dipole_moment(self, atoms=None):
    """Return dipole_moment.

    dipole_moment = ((dipole_vector**2).sum())**0.5/Debye

    """
    self.update()

    dv = self.get_dipole_vector(atoms)

    from ase.units import Debye
    return ((dv ** 2).sum()) ** 0.5 / Debye

Vasp.get_dipole_vector

args = (self, atoms=None)

Tries to return the dipole vector of the unit cell in atomic units.

Returns None when CHG file is empty/not-present.

Monkey-patch defined in vasp/getters.py at line 405

./vasp/getters.py::405

@monkeypatch_class(vasp.Vasp)
def get_dipole_vector(self, atoms=None):
    """Tries to return the dipole vector of the unit cell in atomic units.

    Returns None when CHG file is empty/not-present.

    """
    self.update()

    from POTCAR import get_ZVAL

    if atoms is None:
        atoms = self.get_atoms()

    try:
        x, y, z, cd = self.get_charge_density()
    except (IOError, IndexError):
        # IOError: no CHG file, function called outside context manager
        # IndexError: Empty CHG file, Vasp run with lcharg=False
        return None

    n0, n1, n2 = cd.shape

    nelements = n0 * n1 * n2
    voxel_volume = atoms.get_volume() / nelements
    total_electron_charge = -cd.sum() * voxel_volume

    electron_density_center = np.array([(cd * x).sum(),
                                        (cd * y).sum(),
                                        (cd * z).sum()])
    electron_density_center *= voxel_volume
    electron_density_center /= total_electron_charge

    electron_dipole_moment = electron_density_center * total_electron_charge
    electron_dipole_moment *= -1.0

    # now the ion charge center
    LOP = self.get_pseudopotentials()
    ppp = os.environ['VASP_PP_PATH']

    # make dictionary for ease of use
    zval = {}
    for sym, ppath, hash in LOP:
        fullpath = os.path.join(ppp, ppath)
        z = get_ZVAL(fullpath)
        zval[sym] = z

    ion_charge_center = np.array([0.0, 0.0, 0.0])
    total_ion_charge = 0.0
    for atom in atoms:
        Z = zval[atom.symbol]
        total_ion_charge += Z
        pos = atom.position
        ion_charge_center += Z * pos

    ion_charge_center /= total_ion_charge
    ion_dipole_moment = ion_charge_center * total_ion_charge

    dipole_vector = (ion_dipole_moment + electron_dipole_moment)

    return dipole_vector

Vasp.get_eigenvalues

args = (self, kpt=0, spin=1)

Return array of eigenvalues for kpt and spin.

Monkey-patch defined in vasp/getters.py at line 144

./vasp/getters.py::144

@monkeypatch_class(vasp.Vasp)
def get_eigenvalues(self, kpt=0, spin=1):
    """Return array of eigenvalues for kpt and spin."""
    self.update()
    log.debug('kpt={} spin={}'.format(kpt, spin))

    with open(os.path.join(self.directory,
                           'vasprun.xml')) as f:
        tree = ElementTree.parse(f)
        path = '/'.join(['calculation',
                         'eigenvalues',
                         'array',
                         'set',
                         "set[@comment='spin {}']",
                         "set[@comment='kpoint {}']"])
        path = path.format(spin + 1, kpt + 1)
        log.debug('path={}'.format(path))
        # Vasp seems to start at 1 not 0
        fields = tree.find(path)

        return np.array([float(x.text.split()[0]) for x in fields])

Vasp.get_elapsed_time

args = (self)

Return elapsed calculation time in seconds from the OUTCAR file.

Monkey-patch defined in vasp/getters.py at line 223

./vasp/getters.py::223

@monkeypatch_class(vasp.Vasp)
def get_elapsed_time(self):
    """Return elapsed calculation time in seconds from the OUTCAR file."""
    self.update()
    import re
    regexp = re.compile('Elapsed time \(sec\):\s*(?P<time>[0-9]*\.[0-9]*)')

    with open(os.path.join(self.directory, 'OUTCAR')) as f:
        lines = f.readlines()

    # fragile but fast.
    m = re.search(regexp, lines[-8])

    time = m.groupdict().get('time', None)
    if time is not None:
        return float(time)
    else:
        return None

Vasp.get_electron_density_center

args = (self, spin=0, scaled=True)

Returns center of electron density. If scaled, use scaled coordinates, otherwise use cartesian coordinates.

Monkey-patch defined in vasp/getters.py at line 377

./vasp/getters.py::377

@monkeypatch_class(vasp.Vasp)
def get_electron_density_center(self, spin=0, scaled=True):
    """Returns center of electron density.
    If scaled, use scaled coordinates, otherwise use cartesian
    coordinates.
    """
    self.update()
    atoms = self.get_atoms()

    x, y, z, cd = self.get_charge_density(spin)
    n0, n1, n2 = cd.shape
    nelements = n0 * n1 * n2
    voxel_volume = atoms.get_volume() / nelements
    total_electron_charge = cd.sum() * voxel_volume

    electron_density_center = np.array([(cd * x).sum(),
                                        (cd * y).sum(),
                                        (cd * z).sum()])
    electron_density_center *= voxel_volume
    electron_density_center /= total_electron_charge

    if scaled:
        uc = atoms.get_cell()
        return np.dot(np.linalg.inv(uc.T), electron_density_center.T).T
    else:
        return electron_density_center

Vasp.get_elf

args = (self)

Returns x, y, z and electron localization function arrays.

Monkey-patch defined in vasp/getters.py at line 364

./vasp/getters.py::364

@monkeypatch_class(vasp.Vasp)
def get_elf(self):
    """Returns x, y, z and electron localization function arrays."""
    assert self.parameters.get('lelf', None) is True,\
        "lelf is not set to True!"

    self.update()
    fname = os.path.join(self.directory, 'ELFCAR')
    x, y, z, data = get_volumetric_data(self, filename=fname)
    atoms = self.get_atoms()
    return x, y, z, data[0] * atoms.get_volume()

Vasp.get_fermi_level

args = (self)

Return the Fermi level.

Monkey-patch defined in vasp/getters.py at line 167

./vasp/getters.py::167

@monkeypatch_class(vasp.Vasp)
def get_fermi_level(self):
    """Return the Fermi level."""
    self.update()

    with open(os.path.join(self.directory,
                           'vasprun.xml')) as f:
        tree = ElementTree.parse(f)
        path = '/'.join(['calculation',
                         'dos',
                         "i[@name='efermi']"
                         ])
        return float(tree.find(path).text)

Vasp.get_ibz_k_points

args = (self)

Return the irreducible k-points.

Monkey-patch defined in vasp/getters.py at line 63

./vasp/getters.py::63

@monkeypatch_class(vasp.Vasp)
def get_ibz_k_points(self):
    """Return the irreducible k-points."""
    self.update()
    lines = open(os.path.join(self.directory, 'OUTCAR'), 'r').readlines()
    ibz_kpts = []
    n = 0
    i = 0
    for line in lines:
        if line.rfind('Following cartesian coordinates') > -1:
            m = n + 2
            while i == 0:
                ibz_kpts.append([float(lines[m].split()[p])
                                 for p in range(3)])
                m += 1
                if lines[m] == ' \n':
                    i = 1
        if i == 1:
            continue
        n += 1
    ibz_kpts = np.array(ibz_kpts)
    return np.array(ibz_kpts)

Vasp.get_infrared_intensities

args = (self)

Calculate infrared intensities of vibrational modes.

Returns an array of normalized intensities for each vibrational mode. You should have run the vibrational calculation already. This function does not run it for you.

python translation of # A utility for calculating the vibrational intensities from VASP output (OUTCAR) # (C) David Karhanek, 2011-03-25, ICIQ Tarragona, Spain (www.iciq.es) http://homepage.univie.ac.at/david.karhanek/downloads.html#Entry02

Monkey-patch defined in vasp/vib.py at line 194

./vasp/vib.py::194

@monkeypatch_class(vasp.Vasp)
def get_infrared_intensities(self):
    """Calculate infrared intensities of vibrational modes.

    Returns an array of normalized intensities for each vibrational
    mode. You should have run the vibrational calculation already. This
    function does not run it for you.

    python translation of # A utility for calculating the vibrational
    intensities from VASP output (OUTCAR) # (C) David Karhanek,
    2011-03-25, ICIQ Tarragona, Spain (www.iciq.es)
    http://homepage.univie.ac.at/david.karhanek/downloads.html#Entry02
    """
    assert self.parameters.get('lepsilon', None) is True
    assert self.parameters.get('nwrite', 0) == 3
    assert self.parameters.get('ibrion', 0) == 7

    self.update()

    atoms = read(os.path.join(self.directory, 'POSCAR'), format='vasp')
    NIONS = len(atoms)
    BORN_NROWS = NIONS * 4 + 1

    with open(os.path.join(self.directory, 'OUTCAR'), 'r') as f:
        alltext = f.read()
        f.seek(0)
        alllines = f.readlines()
        f.close()

    if 'BORN' not in alltext:
        raise Exception('Born effective charges missing. '
                        'Did you use IBRION=7 or 8?')

    if 'Eigenvectors after division by SQRT(mass)' not in alltext:
        raise Exception('You must rerun with NWRITE=3 to get '
                        'sqrt(mass) weighted eigenvectors')

    # get the Born charges
    for i, line in enumerate(alllines):
        if 'BORN EFFECTIVE CHARGES' in line:
            break

    BORN_MATRICES = []
    i += 2  # skip a line
    for j in range(NIONS):
        BM = []
        i += 1  # skips the ion count line
        for k in range(3):
            line = alllines[i]
            fields = line.split()
            BM.append([float(x) for x in fields[1:4]])
            i += 1  # advance a line
        BORN_MATRICES.append(BM)

    BORN_MATRICES = np.array(BORN_MATRICES)

    # Get the eigenvectors and eigenvalues.  maybe I can replace this
    # code with my other code. for now I just reproduce the count
    # number of vibs. this gets the number from outcar. it seems like
    # it should be known in advance unless constraints make it hard to
    # tell.

    # the next code in the shell script just copies code to eigenvectors.txt
    for i, line in enumerate(alllines):
        if 'Eigenvectors after division by SQRT(mass)' in line:
            break

    EIG_NVIBS = 0
    for line in alllines[i:]:
        if ('f' in line
            and 'THz' in line
            and 'cm-1' in line):
            EIG_NVIBS += 1

    EIG_NIONS = BORN_NROWS
    # I guess this counts blank rows and non-data rows
    # EIG_NROWS = (EIG_NIONS + 3) * EIG_NVIBS + 3

    # i is where the data starts
    i += 6

    EIGENVALUES = []
    EIGENVECTORS = []
    for j in range(EIG_NVIBS):
        mode = []
        EIGENVALUES.append(alllines[i])  # frequencies are here

        i += 1  # skip the frequency line
        i += 1  # skip the xyz line
        for k in range(3):
            fields = [float(x) for x in alllines[i].split()]
            mode.append(fields[3:])
            i += 1
        EIGENVECTORS.append(mode)
        i += 1  # skip blank line

    EIGENVECTORS = np.array(EIGENVECTORS)

    # now we are ready to compute intensities. see
    # http://othes.univie.ac.at/10117/1/2010-05-05_0547640.pdf, page
    # 21.

    # I(\omega) = \sum_{\alpha=1}^3 |
    # \sum_{l=1}^M \sum_{\beta=1}^3 Z_{\alpha\beta}(l)e_{\beta}(l)|^2

    # omega is the vibrational mode
    # alpha, beta are the cartesian polarizations
    # l is the atom number
    # e_beta is the eigenvector of the mode

    intensities = []

    for mode in range(len(EIGENVECTORS)):
        S = 0  # This is the triple sum
        for alpha in [0, 1, 2]:
            s = 0
            for l in [0, 1, 2]:  # this is the atom number
                for beta in [0, 1, 2]:
                    e = EIGENVECTORS[mode][l]
                    Zab = BORN_MATRICES[l][alpha][beta]

                    s += Zab * e[beta]
            S += s ** 2
        intensities.append(S)

    intensities = np.array(intensities) / max(intensities)
    return intensities

Vasp.get_k_point_weights

args = (self)

Return the k-point weights.

Monkey-patch defined in vasp/getters.py at line 118

./vasp/getters.py::118

@monkeypatch_class(vasp.Vasp)
def get_k_point_weights(self):
    """Return the k-point weights."""
    self.update()

    with open(os.path.join(self.directory,
                           'vasprun.xml')) as f:
        tree = ElementTree.parse(f)
        # each weight is in a <v>w</v> element in this varray
        return np.array([float(x.text) for x in
                         tree.find("kpoints/varray[@name='weights']")])

Vasp.get_local_potential

args = (self)

Returns x, y, z, and local potential arrays

We multiply the data by the volume because we are reusing the charge density code which divides by volume.

Monkey-patch defined in vasp/getters.py at line 349

./vasp/getters.py::349

@monkeypatch_class(vasp.Vasp)
def get_local_potential(self):
    """Returns x, y, z, and local potential arrays

    We multiply the data by the volume because we are reusing the
    charge density code which divides by volume.
    """
    self.update()

    fname = os.path.join(self.directory, 'LOCPOT')
    x, y, z, data = get_volumetric_data(self, filename=fname)
    atoms = self.get_atoms()
    return x, y, z, data[0] * atoms.get_volume()

Vasp.get_neb

args = (self, npi=1)

Returns images, energies if available or runs the job.

npi = cores per image for running the calculations. Default=1

show: if True show an NEB plot

Monkey-patch defined in vasp/neb.py at line 46

./vasp/neb.py::46

@monkeypatch_class(vasp.Vasp)
def get_neb(self, npi=1):
    """Returns images, energies if available or runs the job.

    npi = cores per image for running the calculations. Default=1

    show: if True show an NEB plot
    """
    if self.in_queue():
        return self.neb, [None for a in self.neb]

    calc_required = False

    # check for OUTCAR in each image dir
    for i in range(1, len(self.neb) - 1):
        wf = '{0}/OUTCAR'.format(str(i).zfill(2))
        wf = os.path.join(self.directory, wf)
        if not os.path.exists(wf):
            calc_required = True
            break
        else:
            # there was an OUTCAR, now we need to check for
            # convergence.
            done = False
            with open(wf) as f:
                for line in f:
                    if ('reached required accuracy - stopping structural'
                        ' energy minimisation') in line:
                        done = True
                        break
            if not done:
                calc_required = True
                break

    if calc_required:
        # this creates the directories and files if needed.  write out
        # all the images, including initial and final
        if not os.path.isdir(self.directory):
            os.makedirs(self.directory)

        self.set(images=len(self.neb) - 2)
        self.write_incar()
        self.write_kpoints()
        self.write_potcar()
        self.write_db()

        for i, atoms in enumerate(self.neb):
            # zero-padded directory name
            image_dir = os.path.join(self.directory, str(i).zfill(2))
            if not os.path.isdir(image_dir):
                # create if needed.
                os.makedirs(image_dir)
                write_vasp('{0}/POSCAR'.format(image_dir),
                           atoms[self.resort],
                           symbol_count=self.symbol_count)

        # The first and last images need to have real calculators on
        # them so we can write out a DB entry. We need this so we can
        # get the energies on the end-points. Otherwise, there doesn't
        # seem to be a way to do that short of cloning the whole
        # calculation into the end-point directories.

        self.write_db(self.neb[0],
                      os.path.join(self.directory,
                                   '00/DB.db'))

        self.write_db(self.neb[-1],
                      os.path.join(self.directory,
                                   '0{}/DB.db'.format(len(self.neb) - 1)))

        VASPRC['queue.ppn'] = npi * (len(self.neb) - 2)
        log.debug('Running on %i cores', VASPRC['queue.ppn'])

        self.calculate()  # this will raise VaspSubmitted
        return self.neb, [None for a in self.neb]

    #############################################
    # now we are just retrieving results
    energies = []
    import ase.io
    atoms0 = ase.io.read(os.path.join(self.directory,
                                      '00',
                                      'DB.db'))
    energies += [atoms0.get_potential_energy()]

    for i in range(1, len(self.neb) - 1):
        atoms = ase.io.read(os.path.join(self.directory,
                                         str(i).zfill(2),
                                         'CONTCAR'))[self.resort]
        self.neb[i].positions = atoms.positions
        self.neb[i].cell = atoms.cell

        energy = None
        with open(os.path.join(self.directory,
                               str(i).zfill(2),
                               'OUTCAR')) as f:
            for line in f:
                if 'free energy    TOTEN  =' in line:
                    energy = float(line.split()[4])

        energies += [energy]

    fname = os.path.join(self.directory,
                         '0{}/DB.db'.format(len(self.neb) - 1))
    atoms_end = ase.io.read(fname)
    energies += [atoms_end.get_potential_energy()]

    energies = np.array(energies)
    energies -= energies[0]

    return (self.neb, np.array(energies))

Vasp.get_number_of_spins

args = (self)

Returns number of spins. 1 if not spin-polarized 2 if spin-polarized

Monkey-patch defined in vasp/getters.py at line 131

./vasp/getters.py::131

@monkeypatch_class(vasp.Vasp)
def get_number_of_spins(self):
    """Returns number of spins.
    1 if not spin-polarized
    2 if spin-polarized

    """
    if 'ispin' in self.parameters:
        return 2
    else:
        return 1

Vasp.get_occupation_numbers

args = (self, kpt=0, spin=0)

Return the occupation of each k-point.

Monkey-patch defined in vasp/getters.py at line 87

./vasp/getters.py::87

@monkeypatch_class(vasp.Vasp)
def get_occupation_numbers(self, kpt=0, spin=0):
    """Return the occupation of each k-point."""
    self.update()
    lines = open(os.path.join(self.directory, 'OUTCAR')).readlines()
    nspins = self.get_number_of_spins()
    start = 0
    if nspins == 1:
        for n, line in enumerate(lines):  # find it in the last iteration
            m = re.search(' k-point *' + str(kpt + 1) + ' *:', line)
            if m is not None:
                start = n
    else:
        for n, line in enumerate(lines):
            # find it in the last iteration
            if line.find(' spin component ' + str(spin + 1)) != -1:
                start = n
        for n2, line2 in enumerate(lines[start:]):
            m = re.search(' k-point *' + str(kpt + 1) + ' *:', line2)
            if m is not None:
                start = start + n2
                break
    for n2, line2 in enumerate(lines[start + 2:]):
        if not line2.strip():
            break
        occ = []
        for line in lines[start + 2:start + 2 + n2]:
            occ.append(float(line.split()[2]))
    return np.array(occ)

Vasp.get_pseudopotentials

args = (self)

Return list of (symbol, path, git-hash) for each POTCAR.

Monkey-patch defined in vasp/getters.py at line 483

./vasp/getters.py::483

@monkeypatch_class(vasp.Vasp)
def get_pseudopotentials(self):
    """Return list of (symbol, path, git-hash) for each POTCAR."""
    symbols = [x[0] for x in self.ppp_list]
    paths = [x[1] for x in self.ppp_list]
    hashes = []
    vasp_pp_path = os.environ['VASP_PP_PATH']
    for ppp in paths:
        with open(os.path.join(vasp_pp_path, ppp), 'r') as f:
            data = f.read()

        s = sha1()
        s.update("blob %u\0" % len(data))
        s.update(data)
        hashes.append(s.hexdigest())

    return zip(symbols, paths, hashes)

Vasp.get_state

args = (self)

Determine calculation state based on directory contents.

Returns an integer for the state.

./vasp/vasp_core.py::593

def get_state(self):
    """Determine calculation state based on directory contents.

    Returns an integer for the state.

    """

    base_input = [os.path.exists(os.path.join(self.directory, f))
                  for f in ['INCAR', 'POSCAR', 'POTCAR', 'KPOINTS']]

    # Check for NEB first.
    if (np.array([os.path.exists(os.path.join(self.directory, f))
                  for f in ['INCAR', 'POTCAR', 'KPOINTS']]).all()
        and not os.path.exists(os.path.join(self.directory, 'POSCAR'))
        and os.path.isdir(os.path.join(self.directory, '00'))):
        return Vasp.NEB

    # Some input does not exist
    if False in base_input:
        # some input file is missing
        return Vasp.EMPTY

    # Input files exist, but no jobid, and no output
    if (np.array(base_input).all()
        and self.get_db('jobid') is not None
        and not os.path.exists(os.path.join(self.directory, 'OUTCAR'))):
        return Vasp.NEW

    # INPUT files exist, a jobid in the queue
    if self.in_queue():
        return Vasp.QUEUED

    # Not in queue, and finished
    if not self.in_queue():
        if os.path.exists(self.outcar):
            with open(self.outcar) as f:
                lines = f.readlines()
                if 'Voluntary context switches:' in lines[-1]:
                    return Vasp.FINISHED

    # Not in queue, and not finished
    if not self.in_queue():
        if os.path.exists(self.outcar):
            with open(self.outcar) as f:
                lines = f.readlines()
                if 'Voluntary context switches:' not in lines[-1]:
                    return Vasp.NOTFINISHED
        else:
            return Vasp.NOTFINISHED

    # Not in queue, and not finished, with empty contcar
    if not self.in_queue():
        if os.path.exists(self.contcar):
            with open(self.contcar) as f:
                if f.read() == '':
                    return Vasp.EMPTYCONTCAR

    return Vasp.UNKNOWN

Vasp.get_valence_electrons

args = (self)

Return the number of valence electrons for the atoms. Calculated from the POTCAR file.

Monkey-patch defined in vasp/getters.py at line 263

./vasp/getters.py::263

@monkeypatch_class(vasp.Vasp)
def get_valence_electrons(self):
    """Return the number of valence electrons for the atoms.
    Calculated from the POTCAR file.
    """

    default_electrons = self.get_default_number_of_electrons()

    d = {}
    for s, n in default_electrons:
        d[s] = n
    atoms = self.get_atoms()

    nelectrons = 0
    for atom in atoms:
        nelectrons += d[atom.symbol]
    return nelectrons

Vasp.get_vibrational_frequencies

args = (self)

Returns an array of frequencies in wavenumbers.

You should have run the calculation already. This function does not run a calculation.

Monkey-patch defined in vasp/vib.py at line 155

./vasp/vib.py::155

@monkeypatch_class(vasp.Vasp)
def get_vibrational_frequencies(self):
    """Returns an array of frequencies in wavenumbers.

    You should have run the calculation already. This function does not
    run a calculation.
    """
    self.update()
    atoms = self.get_atoms()
    N = len(atoms)

    frequencies = []

    f = open(os.path.join(self.directory, 'OUTCAR'), 'r')
    while True:
        line = f.readline()
        if line.startswith(' Eigenvectors and eigenvalues'
                           ' of the dynamical matrix'):
            break
    f.readline()  # skip ------
    f.readline()  # skip two blank lines
    f.readline()
    for i in range(3 * N):
        # the next line contains the frequencies
        line = f.readline()
        fields = line.split()

        if 'f/i=' in line:  # imaginary frequency
            # frequency in wave-numbers
            frequencies.append(complex(float(fields[6]), 0j))
        else:
            frequencies.append(float(fields[7]))
        # now skip 1 one line, a line for each atom, and a blank line
        for j in range(1 + N + 1):
            f.readline()  # skip the next few lines
    f.close()
    return frequencies

Vasp.get_vibrational_modes

args = (self, mode=None, massweighted=False, show=False, npoints=30, amplitude=0.5)

Read the OUTCAR and get the eigenvectors. Return value depends on the arguments.

mode= None returns all modes mode= 2 returns mode 2 mode=[1, 2] returns modes 1 and 2

massweighted = True returns sqrt(mass) weighted eigenvectors. E.g. M * evectors * M

show=True makes a trajectory that can be visualized npoints = number of points in the trajectory amplitude = magnitude of the vibrations

some special cases to handle: ibrion=5 + selective dynamics may lead to unexpected number of modes

if nwrite=3, there will be a sqrt(mass) weighted vectors and two sets of vectors.

I am not sure if these eigenvectors are mass-weighted. And I am not sure if the order of the eigenvectors in OUTCAR is the same as the atoms.

Note: it seems like it might be much easier to get this out of vasprun.xml

Monkey-patch defined in vasp/vib.py at line 13

./vasp/vib.py::13

@monkeypatch_class(vasp.Vasp)
def get_vibrational_modes(self,
                          mode=None,
                          massweighted=False,
                          show=False,
                          npoints=30,
                          amplitude=0.5):

    """Read the OUTCAR and get the eigenvectors. Return value depends
    on the arguments.

    mode= None returns all modes
    mode= 2 returns mode 2
    mode=[1, 2] returns modes 1 and 2

    massweighted = True returns sqrt(mass) weighted
    eigenvectors. E.g. M * evectors * M

    show=True makes a trajectory that can be visualized
    npoints = number of points in the trajectory
    amplitude = magnitude of the vibrations

    some special cases to handle:
    ibrion=5 + selective dynamics
       may lead to unexpected number of modes

    if nwrite=3, there will be a sqrt(mass) weighted vectors
    and two sets of vectors.

    I am not sure if these eigenvectors are mass-weighted. And I am
    not sure if the order of the eigenvectors in OUTCAR is the same as
    the atoms.

    Note: it seems like it might be much easier to get this out of
    vasprun.xml
    """
    self.update()

    atoms = self.get_atoms()

    if hasattr(atoms, 'constraints') and self.parameters['ibrion'] == 5:
        # count how many modes to get.
        NMODES = 0
        f = open(os.path.join(self.directory, 'OUTCAR'))
        for line in f:
            if ('f' in line and 'THz' in line and 'cm-1' in line):
                NMODES += 1
        f.close()
    else:
        NMODES = 3 * len(atoms)

    frequencies, eigenvectors = [], []

    # now we find where the data starts. I think the unweighted
    # vectors always come first. if nwrite=3, then there are
    # sqrt(mass) weighted vectors that follow this section

    f = open(os.path.join(self.directory, 'OUTCAR'), 'r')
    while True:
        line = f.readline()
        if line.startswith(' Eigenvectors and eigenvalues'
                           ' of the dynamical matrix'):
            break
    f.readline()   # skip ------
    f.readline()   # skip two blank lines
    f.readline()

    for i in range(NMODES):
        freqline = f.readline()
        fields = freqline.split()

        if 'f/i=' in freqline:  # imaginary frequency
            frequencies.append(complex(float(fields[-2]) * 0.001, 0j))
        else:
            frequencies.append(float(fields[-2]) * 0.001)
        #        X         Y         Z           dx          dy          dz
        f.readline()
        thismode = []
        for i in range(len(atoms)):
            line = f.readline().strip()
            X, Y, Z, dx, dy, dz = [float(x) for x in line.split()]
            thismode.append(np.array([dx, dy, dz]))
        f.readline()  # blank line

        thismode = np.array(thismode)
        # now we need to resort the vectors in this mode so they match
        # the atoms order
        thismode = thismode[self.resort]

        if massweighted:
            # construct M
            numbers = [a.get('number') for a in atoms]
            M = []
            for i in range(len(atoms)):
                for j in range(3):
                    an = numbers[i]
                    M.append(1. / np.sqrt(atomic_masses[an]))
            M = np.array(M)
            M = np.diag(M)  # diagonal array

            thismode = np.dot(M, thismode.flat)

            thismode = thismode.reshape((len(atoms), 3))
        # renormalize the mode
        mag = np.linalg.norm(thismode)
        thismode /= mag

        eigenvectors.append(thismode)
    f.close()

    eigenvectors = np.array(eigenvectors)

    if mode is None:
        retval = (frequencies, eigenvectors)
    else:
        retval = (frequencies[mode], eigenvectors[mode])

    if show:
        from ase.visualize import view
        if mode is None:
            mode = [0]
        elif not isinstance(mode, list):
            mode = [mode]  # make a list for next code

        # symmetric path from -1 to 1 to -1
        X = np.append(np.linspace(0, 1, npoints / 3),
                      np.linspace(1, -1, npoints / 3))
        X = np.append(X,
                      np.linspace(-1, 0, npoints / 3))
        X *= amplitude

        for m in mode:
            traj = []
            for i, x in enumerate(X):
                a = atoms.copy()
                a.positions += x * eigenvectors[m]
                traj += [a]

            view(traj)
    return retval

Vasp.get_volumetric_data

args = (self, filename=None, **kwargs)

Read filename to read the volumetric data in it. Supported filenames are CHG, CHGCAR, and LOCPOT.

Monkey-patch defined in vasp/getters.py at line 282

./vasp/getters.py::282

@monkeypatch_class(vasp.Vasp)
def get_volumetric_data(self, filename=None, **kwargs):
    """Read filename to read the volumetric data in it.
    Supported filenames are CHG, CHGCAR, and LOCPOT.
    """
    self.update()
    if filename is None:
        filename = os.path.join(self.directory, 'CHG')

    from VaspChargeDensity import VaspChargeDensity

    atoms = self.get_atoms()
    vd = VaspChargeDensity(filename)

    data = np.array(vd.chg)
    n0, n1, n2 = data[0].shape

    # This is the old code, but it doesn't seem to work anymore.
    # s0 = np.linspace(0, 1, num=n0, endpoint=False)
    # s1 = np.linspace(0, 1, num=n1, endpoint=False)
    # s2 = np.linspace(0, 1, num=n2, endpoint=False)

    # X, Y, Z = np.meshgrid(s0, s1, s2)

    s0 = 1.0 / n0
    s1 = 1.0 / n1
    s2 = 1.0 / n2
    X, Y, Z = np.mgrid[0.0:1.0:s0,
                       0.0:1.0:s1,
                       0.0:1.0:s2]

    C = np.column_stack([X.ravel(),
                         Y.ravel(),
                         Z.ravel()])

    uc = atoms.get_cell()
    real = np.dot(C, uc)

    # now convert arrays back to unitcell shape
    x = np.reshape(real[:, 0], (n0, n1, n2))
    y = np.reshape(real[:, 1], (n0, n1, n2))
    z = np.reshape(real[:, 2], (n0, n1, n2))
    return (x, y, z, data)

Vasp.in_queue

args = (self)

Return True or False if the directory has a job in the queue.

Monkey-patch defined in vasp/runner.py at line 30

./vasp/runner.py::30

@monkeypatch_class(vasp.Vasp)
def in_queue(self):
    """Return True or False if the directory has a job in the queue."""
    if self.get_db('jobid') is None:
        log.debug('jobid not found for calculation.')
        return False
    else:
        # get the jobid
        jobid = self.get_db('jobid')
        # see if jobid is in queue
        _, jobids_in_queue, _ = getstatusoutput('qselect',
                                                stdout=subprocess.PIPE,
                                                stderr=subprocess.PIPE)

        if str(jobid) in jobids_in_queue.split('\n'):
            # get details on specific jobid in case it is complete
            status, output, err = getstatusoutput(['qstat', jobid],
                                                  stdout=subprocess.PIPE,
                                                  stderr=subprocess.PIPE)
            if status == 0:
                lines = output.split('\n')
                fields = lines[2].split()
                job_status = fields[4]
                if job_status == 'C':
                    return False
                else:
                    return True
        else:
            return False

Vasp.plot_neb

args = (self, show=True)

Return a list of the energies and atoms objects for each image in

the band.

by default shows the plot figure

Monkey-patch defined in vasp/neb.py at line 159

./vasp/neb.py::159

@monkeypatch_class(vasp.Vasp)
def plot_neb(self, show=True):
    """Return a list of the energies and atoms objects for each image in

    the band.

    by default shows the plot figure
    """
    images, energies = self.get_neb()
    # add fitted line to band energies. we make a cubic spline
    # interpolating function of the negative energy so we can find the
    # minimum which corresponds to the barrier
    from scipy.interpolate import interp1d
    from scipy.optimize import fmin
    f = interp1d(range(len(energies)),
                 -energies,
                 kind='cubic', bounds_error=False)
    x0 = len(energies) / 2.  # guess barrier is at half way
    xmax = fmin(f, x0)

    xfit = np.linspace(0, len(energies) - 1)
    bandfit = -f(xfit)

    import matplotlib.pyplot as plt
    p = plt.plot(energies - energies[0], 'bo ', label='images')
    plt.plot(xfit, bandfit, 'r-', label='fit')
    plt.plot(xmax, -f(xmax), '* ', label='max')
    plt.xlabel('Image')
    plt.ylabel('Energy (eV)')
    s = ['$\Delta E$ = {0:1.3f} eV'.format(float(energies[-1]
                                                 - energies[0])),
         '$E^\ddag$ = {0:1.3f} eV'.format(float(-f(xmax)))]

    plt.title('\n'.join(s))
    plt.legend(loc='best', numpoints=1)
    if show:
        from ase.calculators.singlepoint import SinglePointCalculator
        from ase.visualize import view
        # It seems there might be some info on the atoms that causes
        # an error here. Making a copy seems to get rid of the
        # issue. Hacky.
        tatoms = [x.copy() for x in images]
        for i, x in enumerate(tatoms):
            x.set_calculator(SinglePointCalculator(x, energy=energies[i]))
        view(tatoms)
        plt.show()
    return p

Vasp.read

args = (self, restart=None)

Read the files in a calculation if they exist.

restart is ignored, but part of the signature for ase. I am not sure what we could use it for.

sets self.parameters and atoms.

Monkey-patch defined in vasp/readers.py at line 220

./vasp/readers.py::220

@monkeypatch_class(vasp.Vasp)
def read(self, restart=None):
    """Read the files in a calculation if they exist.

    restart is ignored, but part of the signature for ase. I am not
    sure what we could use it for.

    sets self.parameters and atoms.

    """

    self.neb = None
    # NEB is special and handled separately
    if self.get_state() == vasp.Vasp.NEB:
        self.read_neb()
        return

    # Else read a regular calculation. we start with reading stuff
    # that is independent of the calculation state.
    self.parameters = Parameters()

    if os.path.exists(self.incar):
        self.parameters.update(self.read_incar())
    if os.path.exists(self.potcar):
        self.parameters.update(self.read_potcar())
    if os.path.exists(self.kpoints):
        self.parameters.update(self.read_kpoints())

    # We have to figure out the xc that was used based on the
    # Parameter keys.  We sort the possible xc dictionaries so the
    # ones with the largest number of keys are compared first. This is
    # to avoid false matches of xc's with smaller number of equal
    # keys.
    xc_keys = sorted(vasp.Vasp.xc_defaults,
                     key=lambda k: len(vasp.Vasp.xc_defaults[k]),
                     reverse=True)

    for ex in xc_keys:
        pd = {k: self.parameters.get(k, None)
              for k in vasp.Vasp.xc_defaults[ex]}
        if pd == vasp.Vasp.xc_defaults[ex]:
            self.parameters['xc'] = ex
            break

    # reconstruct ldau_luj. special setups might break this.
    if 'ldauu' in self.parameters:
        ldaul = self.parameters['ldaul']
        ldauj = self.parameters['ldauj']
        ldauu = self.parameters['ldauu']

        with open(self.potcar) as f:
            lines = f.readlines()

        # symbols are in the first line of each potcar
        symbols = [lines[0].split()[1]]
        for i, line in enumerate(lines):
            if 'End of Dataset' in line and i != len(lines) - 1:
                symbols += [lines[i + 1].split()[1]]

        ldau_luj = {}
        for sym, l, j, u in zip(symbols, ldaul, ldauj, ldauu):
            ldau_luj[sym] = {'L': l, 'U': u, 'J': j}

        self.parameters['ldau_luj'] = ldau_luj

    # Now for the atoms. This does depend on the state. self.resort
    # needs to be a list for shuffling constraints if they exist.
    self.resort = self.get_db('resort')
    if self.resort is not None:
        self.resort = list(self.resort)

    import ase.io
    contcar = os.path.join(self.directory, 'CONTCAR')
    empty_contcar = False
    if os.path.exists(contcar):
        # make sure the contcar is not empty
        with open(contcar) as f:
            if f.read() == '':
                empty_contcar = True

    poscar = os.path.join(self.directory, 'POSCAR')

    if os.path.exists(contcar) and not empty_contcar:
        atoms = ase.io.read(contcar)
    elif os.path.exists(poscar):
        atoms = ase.io.read(poscar)
    else:
        atoms = None

    if atoms is not None:
        atoms = atoms[self.resort]
        self.sort_atoms(atoms)

    self.read_results()

Vasp.read_incar

args = (self, fname=None)

Read fname (defaults to INCAR).

Returns a Parameters dictionary from the INCAR.

This only reads simple INCAR files, e.g. one tag per line, and with no comments in the line. There is no knowledge of any Vasp keywords in this, and the values are converted to Python types by some simple rules.

Monkey-patch defined in vasp/readers.py at line 28

./vasp/readers.py::28

@monkeypatch_class(vasp.Vasp)
def read_incar(self, fname=None):
    """Read fname (defaults to INCAR).

    Returns a Parameters dictionary from the INCAR.

    This only reads simple INCAR files, e.g. one tag per line, and
    with no comments in the line. There is no knowledge of any Vasp
    keywords in this, and the values are converted to Python types by
    some simple rules.

    """

    if fname is None:
        fname = self.incar

    params = Parameters()

    with open(fname) as f:
        lines = f.readlines()

    # The first line is a comment
    for line in lines[1:]:
        line = line.strip()
        if ";" in line:
            raise Exception('; found. that is not supported.')
        if '#' in line:
            raise Exception('# found. that is not supported.')
        if line == '':
            continue

        key, val = line.split('=')
        key = key.strip().lower()
        val = val.strip()
        # now we need some logic
        if val == '.TRUE.':
            val = True
        elif val == '.FALSE.':
            val = False
        # Match integers by a regexp that includes signs
        # val.isdigit() does not get negative integers right.
        elif re.match('^[-+]?\d+$', val):
            val = int(val)
        elif isfloat(val):
            val = float(val)
        elif len(val.split(' ')) > 1:
            # this is some kind of list separated by spaces
            val = val.split(' ')
            val = [int(x) if re.match('^[-+]?\d+$', x)
                   else float(x) for x in val]
        else:
            # I guess we have a string here.
            pass

        # make sure magmom is returned as a list. This is an issue
        # when there is only one atom. Then it looks like a float.
        if key == 'magmom':
            if not isinstance(val, list):
                val = [val]

        params[key] = val

    return params

Vasp.read_kpoints

args = (self, fname=None)

Read KPOINTS file.

Returns a Parameters object of kpoint tags.

Monkey-patch defined in vasp/readers.py at line 93

./vasp/readers.py::93

@monkeypatch_class(vasp.Vasp)
def read_kpoints(self, fname=None):
    """Read KPOINTS file.

    Returns a Parameters object of kpoint tags.

    """

    if fname is None:
        fname = self.kpoints

    with open(fname) as f:
        lines = f.readlines()

    params = Parameters()

    # first line is a comment
    # second line is the number of kpoints or 0 for automatic kpoints
    nkpts = int(lines[1].strip())

    # third line you have to specify whether the coordinates are given
    # in cartesian or reciprocal coordinates if nkpts is greater than
    # zero. Only the first character of the third line is
    # significant. The only key characters recognized by VASP are 'C',
    # 'c', 'K' or 'k' for switching to cartesian coordinates, any
    # other character will switch to reciprocal coordinates.
    #
    # if nkpts = 0 then the third line will start with m or g for
    # Monkhorst-Pack and Gamma. if it does not start with m or g, an
    # alternative mode is entered that we do not support yet.

    ktype = lines[2].split()[0].lower()[0]
    if nkpts <= 0:
        # automatic mode
        if ktype not in ['g', 'm']:
            raise NotImplementedError('Only Monkhorst-Pack and '
                                      'gamma centered grid supported '
                                      'for restart.')
        if ktype == 'g':
            line5 = np.array([float(lines[4].split()[i]) for i in range(3)])
            if (line5 == np.array([0.0, 0.0, 0.0])).all():
                params['gamma'] = True
            else:
                params['gamma'] = line5

        kpts = [int(lines[3].split()[i]) for i in range(3)]
        params['kpts'] = kpts
    elif nkpts > 0:
        # list of kpts provided. Technically c,k are supported and
        # anything else means reciprocal coordinates.
        if ktype in ['c', 'k', 'r']:
            kpts = []
            for i in range(3, 3 + nkpts):
                # the kpts also have a weight attached to them
                kpts.append([float(lines[i].split()[j])
                             for j in range(4)])
            params['kpts'] = kpts
        # you may also be in line-mode
        elif ktype in ['l']:
            if lines[3][0].lower() == 'r':
                params['reciprocal'] = True

            params['kpts_nintersections'] = nkpts

            kpts = []
            for i in range(4, len(lines)):
                if lines[i] == '':
                    continue
                else:
                    kpts.append([float(lines[i].split()[j])
                                 for j in range(3)])
        else:
            raise NotImplementedError('ktype = %s' % lines[2])

    if ktype == 'r':
        params['reciprocal'] = True

    params['kpts'] = kpts
    return params

Vasp.read_neb

args = (self)

Read an NEB calculator.

Monkey-patch defined in vasp/readers.py at line 383

./vasp/readers.py::383

@monkeypatch_class(vasp.Vasp)
def read_neb(self):
    """Read an NEB calculator."""
    import ase
    import glob
    atoms = []
    atoms += [ase.io.read('{}/00/POSCAR'.format(self.directory))]
    for p in glob.glob('{}/0[0-9]/CONTCAR'.format(self.directory)):
        atoms += [ase.io.read(p)]
    atoms += [ase.io.read('{}/0{}/POSCAR'.format(self.directory,
                                                 len(atoms)))]
    self.neb = atoms
    self.parameters = {}
    self.set(images=(len(atoms) - 2))
    self.atoms = atoms[0].copy()

    if os.path.exists(self.incar):
        self.parameters.update(self.read_incar())
    if os.path.exists(self.potcar):
        self.parameters.update(self.read_potcar())
    if os.path.exists(self.kpoints):
        self.parameters.update(self.read_kpoints())

    # Update the xc functional
    xc_keys = sorted(vasp.Vasp.xc_defaults,
                     key=lambda k: len(vasp.Vasp.xc_defaults[k]),
                     reverse=True)

    for ex in xc_keys:
        pd = {k: self.parameters.get(k, None)
              for k in vasp.Vasp.xc_defaults[ex]}
        if pd == vasp.Vasp.xc_defaults[ex]:
            self.parameters['xc'] = ex
            break

Vasp.read_potcar

args = (self, fname=None)

Read the POTCAR file to get the pp and setups.

Returns a Parameters dictionary of pp and setups.

Monkey-patch defined in vasp/readers.py at line 174

./vasp/readers.py::174

@monkeypatch_class(vasp.Vasp)
def read_potcar(self, fname=None):
    """Read the POTCAR file to get the pp and setups.

    Returns a Parameters dictionary of pp and setups.

    """

    if fname is None:
        fname = self.potcar

    params = Parameters()

    potcars = []
    with open(fname) as f:
        lines = f.readlines()

    # first potcar
    potcars += [lines[0].strip()]

    for i, line in enumerate(lines):
        if 'LEXCH  = PE' in line:
            params['pp'] = 'PBE'
        elif 'LEXCH  = CA' in line:
            params['pp'] = 'LDA'
        elif 'LEXCH  = 91' in line:
            params['pp'] = 'GGA'

        if 'End of Dataset' in line and i != len(lines) - 1:
            potcars += [lines[i + 1].strip()]

    potcars = [(x[0], x[1], x[2]) for x in
               [potcar.split() for potcar in potcars]]

    special_setups = []
    for xc, sym, date in potcars:
        if '_' in sym:  # we have a special setup
            symbol, setup = sym.split('_')
            special_setups += [[symbol, '_' + setup]]

    if special_setups:
        params['setups'] = special_setups

    return params

Vasp.read_results

args = (self)

Read energy, forces, stress, magmom and magmoms from output file.

Other quantities will be read by other functions. This depends on state.

Monkey-patch defined in vasp/readers.py at line 316

./vasp/readers.py::316

@monkeypatch_class(vasp.Vasp)
def read_results(self):
    """Read energy, forces, stress, magmom and magmoms from output file.

    Other quantities will be read by other functions. This depends on
    state.

    """
    state = self.get_state()
    if state == vasp.Vasp.NEB:
        # This is handled in self.read()
        return

    if state != vasp.Vasp.FINISHED:
        self.results = {}
    else:
        # regular calculation that is finished
        from ase.io.vasp import read_vasp_xml
        if not os.path.exists(os.path.join(self.directory,
                                           'vasprun.xml')):
            exc = 'No vasprun.xml in {}'.format(self.directory)
            raise exceptions.VaspNotFinished(exc)

        atoms = read_vasp_xml(os.path.join(self.directory,
                                           'vasprun.xml')).next()

        energy = atoms.get_potential_energy()
        forces = atoms.get_forces()  # needs to be resorted
        stress = atoms.get_stress()

        resort = self.get_db('resort')
        if self.atoms is None:
            atoms = atoms[resort]
            self.sort_atoms(atoms)
            self.atoms.set_calculator(self)
        else:
            # update the atoms
            self.atoms.positions = atoms.positions[resort]
            self.atoms.cell = atoms.cell
            imm = self.parameters.get('magmom',
                                      [0 for atom in self.atoms])
            self.atoms.set_initial_magnetic_moments(imm)

        self.results['energy'] = energy
        self.results['forces'] = forces[self.resort]
        self.results['stress'] = stress
        self.results['dipole'] = None
        self.results['charges'] = np.array([None for atom in self.atoms])

        magnetic_moment = 0
        magnetic_moments = np.zeros(len(atoms))
        if self.parameters.get('ispin', 0) == 2:
            lines = open(os.path.join(self.directory, 'OUTCAR'),
                         'r').readlines()
            for n, line in enumerate(lines):
                if line.rfind('number of electron  ') > -1:
                    magnetic_moment = float(line.split()[-1])

                if line.rfind('magnetization (x)') > -1:
                    for m in range(len(atoms)):
                        val = float(lines[n + m + 4].split()[4])
                        magnetic_moments[m] = val

        self.results['magmom'] = magnetic_moment
        self.results['magmoms'] = np.array(magnetic_moments)[self.resort]

Vasp.reset

args = (self)

overwrite to avoid killing self.atoms.

./vasp/vasp_core.py::468

def reset(self):
    """overwrite to avoid killing self.atoms."""
    self.results = {}

Vasp.run

args = (self)

Convenience function to run calculation.

./vasp/vasp_core.py::563

def run(self):
    """Convenience function to run calculation."""
    return self.potential_energy

Vasp.set

args = (self, **kwargs)

Set parameters with keyword=value pairs.

calc.set(xc=’PBE’)

A few special kwargs are handled separately to expand them prior to setting the parameters. This is done to enable one set to track changes.

Monkey-patch defined in vasp/setters.py at line 17

./vasp/setters.py::17

@monkeypatch_class(vasp.Vasp)
def set(self, **kwargs):
    """Set parameters with keyword=value pairs.

    calc.set(xc='PBE')

    A few special kwargs are handled separately to expand them
    prior to setting the parameters. This is done to enable one
    set to track changes.

    """

    if 'xc' in kwargs:
        kwargs.update(self.set_xc_dict(kwargs['xc']))

    if 'ispin' in kwargs:
        kwargs.update(self.set_ispin_dict(kwargs['ispin']))

    if 'ldau_luj' in kwargs:
        kwargs.update(self.set_ldau_luj_dict(kwargs['ldau_luj']))

    if 'nsw' in kwargs:
        kwargs.update(self.set_nsw_dict(kwargs['nsw']))

    changed_parameters = FileIOCalculator.set(self, **kwargs)
    if changed_parameters:
        self.reset()
    return changed_parameters

Vasp.set_ispin_dict

args = (self, val)

Returns dictionary of changes for ispin change.

Monkey-patch defined in vasp/setters.py at line 47

./vasp/setters.py::47

@monkeypatch_class(vasp.Vasp)
def set_ispin_dict(self, val):
    """Returns dictionary of changes for ispin change."""
    # there are two ways to get magmom in.
    # 1. if you use magmom as a keyword, they are used.
    # 2. if you set magmom on each atom in an Atoms object and do not use
    # magmom then we use the atoms magmom, if we have ispin=2 set.
    # we set lorbit to 11 if ispin=2 so we can get the individual moments.
    if val is None:
        d = {}
        for key in ['ispin', 'magmom', 'lorbit']:
            if key in self.parameters:
                d[key] = None
        return d
    elif val == 1:
        d = {'ispin': 1}
        if 'magmom' in self.parameters:
            d['magmom'] = None
        if 'lorbit' in self.parameters:
            d['lorbit'] = None
        return d
    elif val == 2:
        d = {'ispin': 2}
        if 'magmom' not in self.parameters:
            d['magmom'] = [atom.magmom for atom
                            in self.atoms[self.resort]]
        # set individual magnetic moments.
        if 'lorbit' not in self.parameters:
            d['lorbit'] = 11

        return d

Vasp.set_label

args = (self, label)

Set working directory.

In VASP there is no prefix, only the working directory.

./vasp/vasp_core.py::383

def set_label(self, label):
    """Set working directory.

    In VASP there is no prefix, only the working directory.

    """

    if label is None:
        self.directory = os.path.abspath(".")
        self.prefix = None
    else:
        d = os.path.expanduser(label)
        d = os.path.abspath(d)
        self.directory, self.prefix = d, None
        if not os.path.isdir(self.directory):
            os.makedirs(self.directory)

    # Convenient attributes for file names
    for f in ['INCAR', 'POSCAR', 'CONTCAR', 'POTCAR',
              'KPOINTS', 'OUTCAR']:
        fname = os.path.join(self.directory, f)
        setattr(self, f.lower(), fname)

Vasp.set_ldau_luj_dict

args = (self, val)

Set the ldau_luj parameters.

Monkey-patch defined in vasp/setters.py at line 95

./vasp/setters.py::95

@monkeypatch_class(vasp.Vasp)
def set_ldau_luj_dict(self, val):
    """Set the ldau_luj parameters."""
    if 'setups' in self.parameters:
        raise Exception('setups and ldau_luj is not supported.')

    if not hasattr(self, 'ppp_list'):
        atoms = self.get_atoms()
        self.sort_atoms(atoms)

    if val is not None:
        atom_types = [x[0] if isinstance(x[0], str)
                      else self.atoms[x[0]].symbol
                      for x in self.ppp_list]

        d = {}

        d['ldaul'] = [val[sym]['L'] for sym in atom_types]
        d['ldauu'] = [val[sym]['U'] for sym in atom_types]
        d['ldauj'] = [val[sym]['J'] for sym in atom_types]
        return d
    else:
        d = {}
        d['ldaul'] = None
        d['ldauu'] = None
        d['ldauj'] = None
        return d

Vasp.set_nbands

args = (self, N=None, f=1.5)

Convenience function to set NBANDS to N or automatically compute nbands for non-spin-polarized calculations.

nbands = int(nelectrons/2 + nions*f)

this formula is suggested at http://cms.mpi.univie.ac.at/vasp/vasp/NBANDS_tag.html for transition metals f may be as high as 2.

Monkey-patch defined in vasp/setters.py at line 124

./vasp/setters.py::124

@monkeypatch_class(vasp.Vasp)
def set_nbands(self, N=None, f=1.5):
    """Convenience function to set NBANDS to N or automatically compute
    nbands for non-spin-polarized calculations.

    nbands = int(nelectrons/2 + nions*f)

    this formula is suggested at
    http://cms.mpi.univie.ac.at/vasp/vasp/NBANDS_tag.html for
    transition metals f may be as high as 2.

    """
    if N is not None:
        self.set(nbands=int(N))
        return
    atoms = self.get_atoms()
    nelectrons = self.get_valence_electrons()
    nbands = int(np.ceil(nelectrons / 2.) + len(atoms) * f)
    self.set(nbands=nbands)

Vasp.set_nsw_dict

args = (self, val)

Set nsw parameter.

The default lwave behavior is False, but if nsw > 0 it makes sense to turn it on in case of restarts.

Monkey-patch defined in vasp/setters.py at line 145

./vasp/setters.py::145

@monkeypatch_class(vasp.Vasp)
def set_nsw_dict(self, val):
    """Set nsw parameter.

    The default lwave behavior is False, but if nsw > 0 it makes sense
    to turn it on in case of restarts.

    """

    d = {'nsw': val}

    if val > 0:
        d['lwave'] = True
    elif val == 0:
        d['lwave'] = False
    else:
        d['lwave'] = False
    return d

Vasp.set_rwigs_dict

args = (self, val)

Return rwigs parameters.

Monkey-patch defined in vasp/setters.py at line 80

./vasp/setters.py::80

@monkeypatch_class(vasp.Vasp)
def set_rwigs_dict(self, val):
    """Return rwigs parameters."""
    d = {}
    if val is None:
        d['rwigs'] = None
        d['lorbit'] = None
    else:
        # val is a dictionary {sym: rwigs}
        # rwigs needs to be in the order of the potcars
        d['rwigs'] = [val[x[0]] for x in self.ppp_list]

    return d

Vasp.set_xc_dict

args = (self, val)

Set xc parameter.

Adds all the xc_defaults flags for the chosen xc.

Monkey-patch defined in vasp/setters.py at line 165

./vasp/setters.py::165

@monkeypatch_class(vasp.Vasp)
def set_xc_dict(self, val):
    """Set xc parameter.

    Adds all the xc_defaults flags for the chosen xc.

    """
    d = {'xc': val.lower()}
    oxc = self.parameters.get('xc', None)
    if oxc:
        for key in vasp.Vasp.xc_defaults[oxc.lower()]:
            if key in self.parameters:
                d[key] = None
    d.update(vasp.Vasp.xc_defaults[val.lower()])
    return d

Vasp.sort_atoms

args = (self, atoms=None)

Generate resort list, and make list of POTCARs to use.

Returns None.

./vasp/vasp_core.py::282

def sort_atoms(self, atoms=None):
    """Generate resort list, and make list of POTCARs to use.

    Returns None.

    """
    self.resort = None
    self.ppp_list = None
    self.symbol_count = None

    if atoms is None:
        log.debug('Atoms was none.')
        return
    self.atoms = atoms

    # Now we sort the atoms and generate the list of POTCARS
    # We end up with ppp = [(index_or_symbol, potcar_file, count)]
    # and resort_indices
    setups = self.parameters.get('setups', [])
    pp = self.parameters['pp']

    ppp = []  # [(index_or_symbol, potcar_file, count)]

    # indices of original atoms needed to make sorted atoms list
    resort_indices = []

    # First the numeric index setups
    for setup in [x for x in setups if isinstance(x[0], int)]:
        ppp += [[setup[0],
                 'potpaw_{}/{}{}/POTCAR'.format(pp, atoms[setup[0]].symbol,
                                                setup[1]),
                 1]]
        resort_indices += [setup[0]]

    # now the rest of the setups. These are atom symbols
    for setup in [x for x in setups if not isinstance(x[0], int)]:
        symbol = setup[0]
        count = 0
        for i, atom in enumerate(atoms):
            if atom.symbol == symbol and i not in resort_indices:
                count += 1
                resort_indices += [i]

        ppp += [[symbol,
                 'potpaw_{}/{}{}/POTCAR'.format(pp, symbol, setup[1]),
                 count]]
    # now the remaining atoms use default potentials
    # First get the chemical symbols that remain
    symbols = []
    for atom in atoms or []:
        if (atom.symbol not in symbols and
            atom.symbol not in [x[0] for x in ppp]):
            symbols += [atom.symbol]

    for symbol in symbols:
        count = 0
        for i, atom in enumerate(atoms):
            if atom.symbol == symbol and i not in resort_indices:
                resort_indices += [i]
                count += 1
        if count > 0:
            ppp += [[symbol,
                     'potpaw_{}/{}/POTCAR'.format(pp, symbol),
                     count]]

    assert len(resort_indices) == len(atoms), \
        'Sorting error. sort_indices={}'.format(resort_indices)

    assert sum([x[2] for x in ppp]) == len(atoms)

    self.resort = resort_indices
    self.ppp_list = ppp
    self.atoms_sorted = atoms[self.resort]
    self.symbol_count = [(x[0] if isinstance(x[0], str)
                          else atoms[x[0]].symbol,
                          x[2]) for x in ppp]

    return atoms[self.resort]

Vasp.stop_if

args = (self, condition=None)

Stop program if condition is truthy.

./vasp/vasp_core.py::553

def stop_if(self, condition=None):
    """Stop program if condition is truthy."""
    if condition:
        import sys
        sys.exit()

Vasp.update

args = (self, atoms=None)

Updates calculator.

If a calculation is required, run it, otherwise updates results.

./vasp/vasp_core.py::472

def update(self, atoms=None):
    """Updates calculator.

    If a calculation is required,  run it, otherwise updates results.

    """
    if atoms is None:
        atoms = self.get_atoms()

    if self.neb:
        return self.get_neb()

    if self.calculation_required(atoms, ['energy']):
        return self.calculate(atoms)
    else:
        self.read_results()

    return True

Vasp.view

args = (self, index=None)

Visualize the calculation.

./vasp/vasp_core.py::711

def view(self, index=None):
    """Visualize the calculation.

    """
    from ase.visualize import view
    if index is not None:
        return view(self.traj[index])
    else:
        return view(self.traj)

Vasp.wait

args = (self)

Stop program if not ready.

./vasp/vasp_core.py::559

def wait(self):
    """Stop program if not ready."""
    self.stop_if(self.potential_energy is None)

Vasp.write_db

args = (self, atoms=None, fname=None, data=None, **kwargs)

Write the DB file.

atoms can be any atoms object, defaults to self.get_atoms(). fname can be anything, defaults to self.directory/DB.db

data is a dictionary of data to store.

kwargs is key=value pairs to store with the atoms.

Existing data and kwargs are preserved. You can delete kwargs by setting them to None. You can delete data by setting the key to None in the data dictionary.

Only row 1 should be in this database.

Monkey-patch defined in vasp/writers.py at line 31

./vasp/writers.py::31

@monkeypatch_class(vasp.Vasp)
def write_db(self, atoms=None, fname=None, data=None, **kwargs):
    """Write the DB file.

    atoms can be any atoms object, defaults to self.get_atoms().
    fname can be anything, defaults to self.directory/DB.db

    data is a dictionary of data to store.

    kwargs is key=value pairs to store with the atoms.

    Existing data and kwargs are preserved. You can delete kwargs by
    setting them to None. You can delete data by setting the key to
    None in the data dictionary.

    Only row 1 should be in this database.

    """
    from ase.db import connect

    if fname is None:
        fname = os.path.join(self.directory, 'DB.db')

    fdata = {'resort': self.resort,
             'parameters': self.parameters,
             'ppp_list': self.ppp_list}
    fkv = {'path': self.directory}

    # get current data and keywords
    if os.path.exists(fname):

        with connect(fname) as con:
            try:
                temp_atoms = con.get_atoms(id=1,
                                           add_additional_information=True)
                fdata.update(temp_atoms.info['data'])
                fkv.update(temp_atoms.info['key_value_pairs'])
            except KeyError:
                pass

    # Update fdata from input args. None removes keywords and data
    # elements
    if data is not None:
        for key, val in data.iteritems():
            if val is None and key in fdata:
                del fdata[key]
            else:
                fdata.update({key: val})

    # update key-value pairs from input args
    for key, val in kwargs.iteritems():
        # we use None to delete keys
        if val is None and key in fkv:
            del fkv[key]
        elif val is not None:
            fkv.update({key: val})

    if atoms is None:
        atoms = self.get_atoms()

    # TODO: NEB? should contain images?
    # write out in non-append mode.
    with connect(fname, append=False) as con:
        con.write(atoms,
                  data=fdata,
                  **fkv)

Vasp.write_incar

args = (self, incar=None)

Writes out the INCAR file.

Boolean values are written as .TRUE./.FALSE. integers/floats and strings are written out as is lists/tuples are written out as space separated values/

Monkey-patch defined in vasp/writers.py at line 111

./vasp/writers.py::111

@monkeypatch_class(vasp.Vasp)
def write_incar(self, incar=None):
    """Writes out the INCAR file.

    Boolean values are written as .TRUE./.FALSE.
    integers/floats and strings are written out as is
    lists/tuples are written out as space separated values/

    """

    if incar is None:
        incar = os.path.join(self.directory, 'INCAR')

    incar_keys = list(set(self.parameters) - set(self.special_kwargs))
    d = {key: self.parameters[key] for key in incar_keys}

    with open(incar, 'w') as f:
        f.write('INCAR created by Atomic Simulation Environment\n')
        for key, val in d.iteritems():
            key = ' ' + key.upper()
            if val is None:
                # Do not write out None values
                # It is how we delete tags
                pass
            elif isinstance(val, bool):
                s = '.TRUE.' if val else '.FALSE.'
                f.write('{} = {}\n'.format(key, s))
            elif isinstance(val, list) or isinstance(val, tuple):
                s = ' '.join([str(x) for x in val])
                f.write('{} = {}\n'.format(key, s))
            else:
                f.write('{} = {}\n'.format(key, val))

Vasp.write_input

args = (self, atoms=None, properties=None, system_changes=None)

Writes all input files required for a calculation.

Monkey-patch defined in vasp/writers.py at line 17

./vasp/writers.py::17

@monkeypatch_class(vasp.Vasp)
def write_input(self, atoms=None, properties=None, system_changes=None):
    """Writes all input files required for a calculation."""
    # this creates the directory if needed
    FileIOCalculator.write_input(self, atoms, properties, system_changes)

    if 'spring' not in self.parameters:  # do not write if NEB
        self.write_poscar()
    self.write_incar()
    self.write_kpoints()
    self.write_potcar()
    self.write_db()

Vasp.write_kpoints

args = (self, fname=None)

Write out the KPOINTS file.

The KPOINTS file format is as follows:

line 1: a comment line 2: number of kpoints n <= 0 Automatic kpoint generation n > 0 explicit number of kpoints line 3: kpt format if n > 0: C,c,K,k = cartesian coordinates anything else = reciprocal coordinates if n <= 0 M,m,G,g for Monkhorst-Pack or Gamma grid anything else is a special case line 4: if n <= 0, the Monkhorst-Pack grid if n > 0, then a line per kpoint line 5: if n <=0 it is the gamma shift

After the kpts may be tetrahedra, but we do now support that for now.

Monkey-patch defined in vasp/writers.py at line 145

./vasp/writers.py::145

@monkeypatch_class(vasp.Vasp)
def write_kpoints(self, fname=None):
    """Write out the KPOINTS file.

    The KPOINTS file format is as follows:

    line 1: a comment
    line 2: number of kpoints
        n <= 0   Automatic kpoint generation
        n > 0    explicit number of kpoints
    line 3: kpt format
        if n > 0:
            C,c,K,k = cartesian coordinates
            anything else = reciprocal coordinates
        if n <= 0
            M,m,G,g for Monkhorst-Pack or Gamma grid
            anything else is a special case
    line 4: if n <= 0, the Monkhorst-Pack grid
        if n > 0, then a line per kpoint
    line 5: if n <=0 it is the gamma shift

    After the kpts may be tetrahedra, but we do now support that for
    now.

    """
    if fname is None:
        fname = os.path.join(self.directory, 'KPOINTS')

    p = self.parameters

    kpts = p.get('kpts', None)  # this is a list, or None

    if kpts is None:
        NKPTS = None
    elif len(np.array(kpts).shape) == 1:
        NKPTS = 0  # automatic
    else:
        NKPTS = len(p['kpts'])

    # figure out the mode
    if NKPTS == 0 and not p.get('gamma', None):
        MODE = 'm'  # automatic monkhorst-pack
    elif NKPTS == 0 and p.get('gamma', None):
        MODE = 'g'  # automatic gamma monkhorst pack
    # we did not trigger automatic kpoints
    elif p.get('kpts_nintersections', None) is not None:
        MODE = 'l'
    elif p.get('reciprocal', None) is True:
        MODE = 'r'
    else:
        MODE = 'c'

    with open(fname, 'w') as f:
        # line 1 - comment
        f.write('KPOINTS created by Atomic Simulation Environment\n')
        # line 2 - number of kpts
        if MODE in ['c', 'k', 'm', 'g', 'r']:
            f.write('{}\n'.format(NKPTS))
        elif MODE in ['l']:  # line mode, default intersections is 10
            f.write('{}\n'.format(p.get('kpts_nintersections')))

        # line 3
        if MODE in ['m', 'g']:
            if MODE == 'm':
                f.write('Monkhorst-Pack\n')  # line 3
            elif MODE == 'g':
                f.write('Gamma\n')
        elif MODE in ['c', 'k']:
            f.write('Cartesian\n')
        elif MODE in ['l']:
            f.write('Line-mode\n')
        else:
            f.write('Reciprocal\n')

        # line 4
        if MODE in ['m', 'g']:
            f.write('{0} {1} {2}\n'.format(*p.get('kpts', (1, 1, 1))))
        elif MODE in ['c', 'k', 'r']:
            for n in range(NKPTS):
                # I assume you know to provide the weights
                f.write('{0} {1} {2} {3}\n'.format(*p['kpts'][n]))
        elif MODE in ['l']:
            if p.get('reciprocal', None) is False:
                f.write('Cartesian\n')
            else:
                f.write('Reciprocal\n')
            for n in range(NKPTS):
                f.write('{0} {1} {2}\n'.format(*p['kpts'][n]))

        # line 5 - only if we are in automatic mode
        if MODE in ['m', 'g']:
            if p.get('gamma', None) and len(p.get('gamma')) == 3:
                f.write('{0} {1} {2}\n'.format(*p['gamma']))
            else:
                f.write('0.0 0.0 0.0\n')

Vasp.write_poscar

args = (self, fname=None)

Write the POSCAR file.

Monkey-patch defined in vasp/writers.py at line 99

./vasp/writers.py::99

@monkeypatch_class(vasp.Vasp)
def write_poscar(self, fname=None):
    """Write the POSCAR file."""
    if fname is None:
        fname = os.path.join(self.directory, 'POSCAR')

    from ase.io.vasp import write_vasp
    write_vasp(fname,
               self.atoms_sorted,
               symbol_count=self.symbol_count)

Vasp.write_potcar

args = (self, fname=None)

Writes the POTCAR file.

POTCARs are expected in $VASP_PP_PATH.

Monkey-patch defined in vasp/writers.py at line 242

./vasp/writers.py::242

@monkeypatch_class(vasp.Vasp)
def write_potcar(self, fname=None):
    """Writes the POTCAR file.

    POTCARs are expected in $VASP_PP_PATH.

    """
    if fname is None:
        fname = os.path.join(self.directory, 'POTCAR')

    with open(fname, 'wb') as potfile:
        for _, pfile, _ in self.ppp_list:
            pfile = os.path.join(os.environ['VASP_PP_PATH'], pfile)
            with open(pfile) as f:
                potfile.write(f.read())

vasp's People

Contributors

jkitchin avatar jtcrum avatar yqshao avatar zulissi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vasp's Issues

case sensitive file systems.

for example, vasp.py should've been named Vasp.py,
I tried demangling the names and etc, to have get the module working but in the end
the effort is getting bigger than actually copy-pasting snippets from the source.

Working with job schedulers other than PBS

I think there should be an option to specify the job scheduler.
I work with LSF and SLURM. I have to modify vasprc.py, vasprun.py, and runner.py
The vasprc file could have that information so that runner and vasprun can check the environment variables to use the appropriate commands.

Error when visualizing atoms objects

Edit: The following code:

from ase.lattice.cubic import FaceCenteredCubic as fcc
from vasp import Vasp

atoms = fcc('Cu',
            directions=[[0, 1, 1],
                        [1, 0, 1],
                        [1, 1, 0]])

calc = Vasp('failed-ase-view',
            xc='PBE',
            kpts=[10, 10, 10],
            encut=250,
            nsw=0,
            atoms=atoms)

calc.calculate()
: /home-research/jboes/research/tests/failed-ase-view submitted: 1398609.gilgamesh.cheme.cmu.edu
from vasp import Vasp
from ase.visualize import view

calc = Vasp('failed-ase-view')
atoms = calc.get_atoms()
view(atoms)

Produces the following error:

Traceback (most recent call last):
  File "<stdin>", line 25, in <module>
  File "/home-research/jboes/python/ase/ase/visualize/__init__.py", line 49, in view
    write(filename, atoms, format=format)
  File "/home-research/jboes/python/ase/ase/io/formats.py", line 258, in write
    io.write(filename, images, **kwargs)
  File "/home-research/jboes/python/ase/ase/io/trajectory.py", line 310, in write_traj
    trj.write(atoms)
  File "/home-research/jboes/python/ase/ase/io/trajectory.py", line 184, in write
    c.write(prop, x)
  File "/home-research/jboes/python/ase/ase/io/aff.py", line 257, in write
    self.fill(value)
  File "/home-research/jboes/python/ase/ase/io/aff.py", line 195, in fill
    a.tofile(self.fd)
ValueError: cannot write object arrays to a file in binary mode

Important notes: As stated below, the view() function works on the atoms object up until the calculation has finished.

Issue with calculations containing Xe

The database file vasprun.xml stores the symbol for Xe as 'X', which causes problems when you clone a calculation and rerun. (For example, writing the POTCAR will fail because it can't find the correct file for atom X.) This is easily fixed in read_atoms(self) which is monkeypatched in readers.py. Here is the patch:

    if os.path.exists(vasprun_xml):
        atoms = ase.io.read(vasprun_xml)
        for atom in atoms:                  # Patch for X <--> Xe
            if atom.symbol == 'X':
                atom.symbol = 'Xe'
        if resort is not None:
            atoms = atoms[resort]
        atoms.set_tags(tags)

I know this seems terribly esoteric, but XeF2 is a useful and commercially relevant reagent/etchant.

Weird Exception Handler Issue

Hi John,

I am finally switching from jasp to vasp.py. I seem to be seeing this weird error when I first run a calculation and I cant seem to figure out why it gets raised. The calculation seems to be running fine, and the second time I run it I get no errors. Any ideas about what is going on?
@jboes Maybe you know?

#+BEGIN_SRC python
from ase import Atoms, Atom
from vasp import Vasp

co = Atoms([Atom('C', [0, 0, 0]),
            Atom('O', [1.2, 0, 0])],
           cell=(6., 6., 6.))

calc = Vasp('molecules/simple-co',  # output dir
            xc='pbe',  # the exchange-correlation functional
            nbands=6,    # number of bands
            encut=350,    # planewave cutoff
            ismear=1,    # Methfessel-Paxton smearing
            sigma=0.01,  # very small smearing factor for a molecule
            atoms=co)
#print calc.implemented_properties
#print('energy = {0} eV'.format(co.get_potential_energy()))
#print(co.get_forces())
#+END_SRC
#+RESULTS:
: Unhandled exception in Vasp
: Traceback (most recent call last):
:   File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/vasp.py", line 48, in inner
:     return func(self, *args, **kwargs)
:   File "/afs/crc.nd.edu/user/p/pmehta1/ase/ase/calculators/calculator.py", line 388, in get_property
:     raise NotImplementedError
: NotImplementedError

raise child_exception

Dear John,
I had meet some problems when I ran some scripts. For example, I ran the scripts

dft-scripts/scripts-107.py:
from ase.lattice.hexagonal import HexagonalClosedPacked
from vasp import Vasp
import matplotlib.pyplot as plt
atoms = HexagonalClosedPacked(symbol='Ru',
latticeconstant={'a': 2.7,
'c/a': 1.584})
a_list = [2.5, 2.6, 2.7, 2.8, 2.9]
covera_list = [1.4, 1.5, 1.6, 1.7, 1.8]
for a in a_list:
energies = []
for covera in covera_list:
atoms = HexagonalClosedPacked(symbol='Ru',
latticeconstant={'a': a,
'c/a': covera})
wd = 'bulk/Ru/{0:1.2f}-{1:1.2f}'.format(a, covera)
calc = Vasp(wd,
xc='PBE',
# the c-axis is longer than the a-axis, so we use
# fewer kpoints.
kpts=[6, 6, 4],
encut=350,
atoms=atoms)
energies.append(atoms.get_potential_energy())
if not None in energies:
plt.plot(covera_list, energies, label=r'a={0} $\AA$'.format(a))
plt.xlabel('$c/a$')
plt.ylabel('Energy (eV)')
plt.legend()
plt.savefig('images/Ru-covera-scan.png')

the exception was thrown:
Unhandled exception in Vasp
Traceback (most recent call last):
File "/home/geniusshaoming/VASP/vasp-master/vasp/vasp.py", line 48, in inner
return func(self, *args, **kwargs)
File "/home/geniusshaoming/VASP/vasp-master/vasp/runner.py", line 157, in calculate
stderr=subprocess.PIPE)
File "/home/geniusshaoming/VASP/vasp-master/vasp/runner.py", line 25, in getstatusoutput
p = subprocess.Popen(*args, **kwargs)
File "/home/geniusshaoming/anaconda3/envs/VASP/lib/python2.7/subprocess.py", line 390, in init
errread, errwrite)
File "/home/geniusshaoming/anaconda3/envs/VASP/lib/python2.7/subprocess.py", line 1025, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory

I need your help and Thanks!

ZBRENT bracketing errors

Sometimes during conjugate gradient optimizations I get this error (these are the last few lines of my vasp stdout file.

       N       E                     dE             d eps       ncg     rms          rms(c)
DAV:   1    -0.808978395638E+03   -0.10606E-05   -0.49230E-05  2080   0.160E-02    0.333E-02
RMM:   2    -0.808978711288E+03   -0.31565E-03   -0.12893E-04  1630   0.152E-02    0.298E-01
RMM:   3    -0.808978163978E+03    0.54731E-03   -0.10917E-04  1576   0.167E-02    0.806E-02
RMM:   4    -0.808978368321E+03   -0.20434E-03   -0.33170E-05  1336   0.843E-03    0.444E-02
RMM:   5    -0.808978372128E+03   -0.38079E-05   -0.72285E-06   961   0.454E-03
  59 F= -.80897837E+03 E0= -.80897978E+03  d E =-.204339E-02  mag=    -0.3409
 curvature:   0.00 expect dE=-0.247E-08 dE for cont linesearch -0.117E-08
 ZBRENT: interpolating
 opt :   0.6785  next Energy=  -808.979501 (dE=-0.317E-02)
 bond charge predicted
       N       E                     dE             d eps       ncg     rms          rms(c)
DAV:   1    -0.808978358854E+03    0.94668E-05   -0.10023E-05  2032   0.697E-03    0.182E-02
RMM:   2    -0.808978312836E+03    0.46018E-04   -0.97341E-06  1244   0.486E-03
  60 F= -.80897831E+03 E0= -.80898022E+03  d E =-.198409E-02  mag=    -0.3378
 curvature:   0.00 expect dE=-0.405E-09 dE for cont linesearch -0.143E-09
 ZBRENT: interpolating
 opt :   0.6785  next Energy=  -808.979501 (dE=-0.317E-02)
 bond charge predicted
       N       E                     dE             d eps       ncg     rms          rms(c)
DAV:   1    -0.808978272998E+03    0.85855E-04   -0.12172E-05  2032   0.996E-03    0.246E-02
RMM:   2    -0.808978269206E+03    0.37918E-05   -0.29084E-05  1345   0.590E-03
  61 F= -.80897827E+03 E0= -.80898068E+03  d E =-.194046E-02  mag=    -0.3340
 curvature:   0.00 expect dE=-0.338E-09 dE for cont linesearch -0.426E-10
 ZBRENT:  can not reach accuracy
 opt :   0.0000  next Energy=     0.000000 (dE= 0.809E+03)
 bond charge predicted
       N       E                     dE             d eps       ncg     rms          rms(c)
DAV:   1    -0.808977102563E+03    0.11704E-02   -0.10614E-01  3392   0.465E-01    0.338E-01
RMM:   2    -0.809064633783E+03   -0.87531E-01   -0.17818E-02  3195   0.104E-01    0.746E+00
RMM:   3    -0.808928314960E+03    0.13632E+00   -0.17136E-02  2844   0.122E-01    0.621E-01
RMM:   4    -0.808973971408E+03   -0.45656E-01   -0.36113E-03  2723   0.868E-02    0.422E-01
RMM:   5    -0.808976894323E+03   -0.29229E-02   -0.60123E-04  2128   0.386E-02    0.241E-01
RMM:   6    -0.808976679739E+03    0.21458E-03   -0.11445E-04  1662   0.160E-02    0.243E-01
RMM:   7    -0.808976527328E+03    0.15241E-03   -0.10336E-04  1656   0.154E-02    0.236E-01
RMM:   8    -0.808976418689E+03    0.10864E-03   -0.86241E-05  1593   0.155E-02    0.179E-01
RMM:   9    -0.808976445212E+03   -0.26523E-04   -0.54527E-05  1600   0.139E-02
  62 F= -.80897645E+03 E0= -.80897894E+03  d E =-.116469E-03  mag=    -0.3177
 curvature:   0.00 expect dE= 0.000E+00 dE for cont linesearch  0.000E+00
 ZBRENT: fatal error in bracketing
     please rerun with smaller EDIFF, or copy CONTCAR
     to POSCAR and continue

This is a special case of VaspNotFinished (http://cms.mpi.univie.ac.at/vasp-forum/viewtopic.php?t=1856). Usually I can get it to work, by deleting the OUTCAR, and resubmitting the job from CONTCAR. One could even change ibrion if required. In jasp, I would do something like below, so the next time I ran it, the job would be automatically resubmitted.

    with open('OUTCAR') as f:
        lines = f.readlines()

    if 'Voluntary context switches' not in lines[-1]:
        try:
            # -5 line of output contains Zbrent message.
            if 'ZBRENT: fatal error in bracketing' in output[-5]:
                message = ['Zbrent Error in: \n {0} \n'.format(os.getcwd()),
                           'OUTCAR has been deleted.\n', 
                           'Please run your script again to restart from CONTCAR']
                os.unlink('OUTCAR')
                raise VaspZbrentError(''.join(message))
        except IndexError:
            pass            
        output += ['Last 20 lines of OUTCAR:\n']
        output += lines[-20:]
        output += ['=' * 66]
        raise VaspNotFinished(''.join(output))

It might be useful to have it in the new vasp.py.

Two issues with check_state and xc = 'optb88-vdw' (and other xc's)

I am having two problems with check_state returning an incorrect 'True' when performing calculations using xc = 'optb88-vdw'. One is simple to fix, the other I am not quite as sure about. Both problems arise from the comparison between file_params (i.e., the current INCAR) and self.parameters (i.e., the current state of the calculator).

The first problem is straightforward: the current comparison is not robust for float keys:

       if not {k: v for k, v in self.parameters.iteritems()
                 if v is not None} == file_params:

In the specific case of xc = 'optb88-vdw', the problem arises with param1, which is set in xc_defaults to be 'param1': 1.1 / 6.0. I suggest replacing the code above with the following:

       # Make parameter list with rounded floats for comparisons
        f_p = {k:round(v,5) if isinstance(v,float) else v for k,v in file_params.iteritems()}
        s_p = {k:round(v,5) if isinstance(v,float) else v for k,v in self.parameters.iteritems()}
        
        if not {k: v for k, v in s_p.iteritems()
                if v is not None} == f_p:

I don't have strong feelings about rounding to 5 significant digits as opposed to some other number, but this is the number of digits suggested in the section of your book describing core energy calculations.

The second problem has to do with the 'xc' key, which is not stored in the INCAR. Instead, for the case of xc - 'optb88-vdw', the following information is stored in the INCAR/POTCAR:

                  'optb88-vdw': {'pp': 'LDA', 'gga': 'BO', 'luse_vdw': True,
                                  'aggac': 0.0, 'param1': 1.1 / 6.0,
                                  'param2': 0.22},

The problem arises with the following bit of code in check_state:

        for ex in xc_keys:
            pd = {k: file_params.get(k, None)
                  for k in Vasp.xc_defaults[ex]}
            if pd == Vasp.xc_defaults[ex]:
                file_params['xc'] = ex.lower()
                break

Before entering this code, my file_params are:

{'nelmdl': -12, 'kpts': [1, 1, 1], 'aggac': 0.0, 'nelm': 60, 'lcharg': False, 'ibrion': 1, 'gga': 'BO', 'param2': 0.22, 'ediff': 0.0001, 'luse_vdw': True, 'nsw': 120, 'pp': 'LDA', 'prec': 'Normal', 'ismear': 0, 'isif': 2, 'algo': 'Fast', 'lreal': False, 'param1': 0.183333333333, 'lwave': False, 'sigma': 0.05, 'ediffg': -0.02}

and the xc_keys are:

['b3lyp', 'optb86b-vdw', 'optb88-vdw', 'hf', 'beef-vdw', 'vdw-df2', 'hse03', 'optpbe-vdw', 'hse06', 'pbe0', 'm06l', 'revtpss', 'rpbe', 'tpss', 'pbesol', 'revpbe', 'am05', 'lda', 'pbe', 'gga']

Because of this, the search stops when pd = {'pp': 'LDA'}. As a result, xc ends up being set to 'lda', which is incorrect. In other words, the search determines that the POTCAR that is used with optb88-vdw is LDA, so it sets 'xc' to 'lda'

For this specific case, it seems to me that there is no need to determine which 'xc' is appropriate for the current INCAR, because we check all of the subsidiary settings (e.g., gga, luse_vdw,aggac, param1, param2) anyway. As a result, ignoring 'xc' in the comparison would be fine. Having said that, I do not know if this is always the case.

If ignoring 'xc' is generally fine, one solution would be to replace the following code in check_state:

        for ex in xc_keys:
            pd = {k: file_params.get(k, None)
                  for k in Vasp.xc_defaults[ex]}
            if pd == Vasp.xc_defaults[ex]:
                file_params['xc'] = ex.lower()
                break

with

        if 'xc' in self.parameters:
        	file_params['xc'] = self.parameters['xc']

QXcbConnection

In [1]: from vasp import Vasp

In [2]: QXcbConnection: Could not connect to display
Aborted (core dumped)

matplotlib

Hi
I'm trying to use this module for the first time and while installing and testing I got this 'ImportError: No module named matplotlib' error message. Is there a way to bypass this without installing matplotlib?
My python file:

!/usr/bin/env python

from ase import *
from ase.visualize import view
from ase.lattice.surface import *
from ase.calculators.vasp import Vasp
from ase.lattice import bulk
from vasp import Vasp

system = Atoms('H2', positions=[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])
system.center(vacuum=6)
calc = Vasp(prec='Accurate',
xc='PW91',
kpts=(1, 1, 1),
encut=400,nelm=250,sigma=0.01,ediff=1E-5,
ibrion=2,
edifg= -0.01,
nsw=10,
lreal=False)

TypeError When Using Vasp()

Hi developers,
I was just trying out the CO example. However, it produced the following erro. I am pretty new to this. Could you please help me and tell me what probably went wrong?

Traceback (most recent call last): File "CO_ex.py", line 16, in <module> atoms=co) File "/groups/caiw/DFT/vasp-python3/vasp/vasp.py", line 41, in inner return func(self, *args, **kwargs) File "/groups/caiw/DFT/vasp-python3/vasp/vasp_core.py", line 256, in __init__ str(label), atoms) File "/groups/caiw/DFT/vasp-python3/vasp/vasp.py", line 41, in inner return func(self, *args, **kwargs) File "/home/kaiwenwang/.local/lib/python3.7/site-packages/ase/calculators/calculator.py", line 901, in __init__ atoms, **kwargs) File "/groups/caiw/DFT/vasp-python3/vasp/vasp.py", line 41, in inner return func(self, *args, **kwargs) File "/home/kaiwenwang/.local/lib/python3.7/site-packages/ase/calculators/calculator.py", line 501, in __init__ self.read(restart) # read parameters, atoms and results File "/groups/caiw/DFT/vasp-python3/vasp/vasp.py", line 41, in inner return func(self, *args, **kwargs) File "/groups/caiw/DFT/vasp-python3/vasp/readers.py", line 269, in read if self.get_state() == Vasp.NEB: File "/groups/caiw/DFT/vasp-python3/vasp/vasp.py", line 41, in inner return func(self, *args, **kwargs) File "/groups/caiw/DFT/vasp-python3/vasp/vasp_core.py", line 793, in get_state for f in ['INCAR', 'POSCAR', 'POTCAR']] File "/groups/caiw/DFT/vasp-python3/vasp/vasp_core.py", line 793, in <listcomp> for f in ['INCAR', 'POSCAR', 'POTCAR']] File "/groups/caiw/Anaconda/lib/python3.7/posixpath.py", line 80, in join a = os.fspath(a) TypeError: expected str, bytes or os.PathLike object, not NoneType

By the way, I tried using the ase.calculators.vasp and it worked, so I suppose it's not a problem of $VASP_PP_PATH setup?

Much appreciated.

DB.db stumbling on 'charges' entry

I've been struggling with the following error this afternoon:

Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "/home-research/jboes/python/ase/ase/db/core.py", line 283, in get
    rows = list(self.select(selection, limit=2, **kwargs))
  File "/home-research/jboes/python/ase/ase/db/core.py", line 396, in select
    limit=limit, offset=offset, sort=sort):
  File "/home-research/jboes/python/ase/ase/db/sqlite.py", line 529, in _select
    yield self._convert_tuple_to_row(values)
  File "/home-research/jboes/python/ase/ase/db/sqlite.py", line 360, in _convert_tuple_to_row
    dct['charges'] = deblob(values[24])
  File "/home-research/jboes/python/ase/ase/db/sqlite.py", line 616, in deblob
    array = np.frombuffer(buf, dtype)
ValueError: buffer size must be a multiple of element size

I have tried this with and without my changes to the write_db function, and the error seems to be independent of the changes.

It only seems to occur with new calculations, and also only when the write_db function is called in some way. Here are the two code blocks I've been using to test this. If someone could verify so I can know if this is a personal change or not, I'd greatly appreciate it.

from vasp import Vasp
from ase.lattice.surface import fcc111
Vasp.VASPRC['queue.walltime'] = '24:00:00'

atoms = fcc111('Au', [1, 1, 7], a=3.934, vacuum=6.0)

calc = Vasp('vasp-DB-old',
        xc='pbe',
        kpts=[10, 10, 1],
        encut=250,
        nsw=0,
        atoms=atoms)
print(calc.potential_energy)

Run this after the top calculations is finished, which takes about 4 minutes.

from vasp import Vasp
from ase.db import connect

calc = Vasp('vasp-DB-old')
calc.write_db()

db = connect('vasp-DB-old/DB.db')
d = db.get()

data = d.data
data.update(d.key_value_pairs)

for k, v in data.iteritems():
    print k, v

Problems with VASP parallel computing

I installed this package in HPC, and got problems to enable parallel VASP computing.
The script as below:

from ase import Atoms, Atom
from vasp import Vasp
from vasp.vasprc import VASPRC
import os
VASPRC['mode'] = 'run'
co = Atoms([Atom('C', [0, 0, 0]),
            Atom('O', [1.2, 0, 0])],
           cell=(6., 6., 6.))
calc = Vasp(path,  # output dir
            xc='pbe',    # the exchange-correlation functional
            nbands=6,    # number of bands
            encut=350,   # planewave cutoff
            ismear=1,    # Methfessel-Paxton smearing
            sigma=0.01,  # very small smearing factor for a molecule
            atoms=co)

print('energy = {0} eV'.format(co.get_potential_energy()))

This script works well when I use command 'python script.py' in terminal with output:

[c3289@rcglogin test_vasp]$ python script.py
energy = -14.69111507 eV

However, for some big systems, I have to use parallel VASP computing, so I write a bash script to submit this python code. The bash script example as below, which called 4 cpus and 8gb memory:

#!/bin/bash

a=$(basename $(pwd))

cat <<END > $a.job
#!/bin/bash 
#PBS -N $a
#PBS -l select=1:ncpus=4:mem=8gb
#PBS -l walltime=168:00:00
#PBS -k eo

export OMP_NUM_THREADS=1
ulimit -s unlimited
ulimit -a
source ~/.bashrc
source /etc/profile.d/modules.sh
#module load mpi/intel
module load intel/mpi/64/5.1.3/2016.4.258
module load python/3.5.3

echo "Running vasp on 4 cpus" 

# now do it
cd \$PBS_O_WORKDIR
date
python script.py
date

END

#do it
qsub $a.job 
rm -f $a.job

However, when I run this bash script. It raise the error:

Running vasp on 4 cpus
Mon Mar 26 13:45:05 AEDT 2018
 Error reading item 'VCAIMAGES' from file INCAR.
Mon Mar 26 13:45:05 AEDT 2018

There were two reasons caused this:
1, Even though I have called 4 cpus in my bash script. The NPROCS = len(open(os.environ['PBS_NODEFILE']).readlines()) in runner.py is 1.
2, When NPROCS ==1, and run VASP as in serial in 'runner.py', as:

if NPROCS == 1:
# no question. running in serial.
vaspcmd = VASPRC['vasp.executable.serial']
log.debug('NPROCS = 1. running in serial')
exitcode = os.system(vaspcmd)
return exitcode

It did not change the directory. So I added one line in front of line110 of runner.py, as:

if NPROCS == 1:
                # no question. running in serial.
                os.chdir(self.directory)
                vaspcmd = VASPRC['vasp.executable.serial']
                log.debug('NPROCS = 1. running in serial')
                exitcode = os.system(vaspcmd)
                return exitcode

And run the bash script again. The VASP do run, with output:

Running vasp on 1 cpus
Mon Mar 26 14:00:23 AEDT 2018
 running on    1 total cores
 distrk:  each k-point on    1 cores,    1 groups
 distr:  one band on    1 cores,    1 groups
 using from now: INCAR     
 vasp.5.4.1 05Feb16 (build Jun 01 2016 13:32:26) complex                        
  
 POSCAR found :  2 types and       2 ions
 scaLAPACK will be used
 LDA part: xc-table for Pade appr. of Perdew
 POSCAR, INCAR and KPOINTS ok, starting setup
 WARNING: small aliasing (wrap around) errors must be expected
 FFT: planning ...
 WAVECAR not read
 entering main loop
       N       E                     dE             d eps       ncg     rms          rms(c)
DAV:   1     0.632077036031E+02    0.63208E+02   -0.28209E+03    12   0.851E+02
DAV:   2    -0.519599844879E+01   -0.68404E+02   -0.68404E+02    18   0.240E+02
DAV:   3    -0.148556863982E+02   -0.96597E+01   -0.96597E+01    12   0.977E+01
DAV:   4    -0.152887386129E+02   -0.43305E+00   -0.43363E+00    24   0.160E+01
DAV:   5    -0.152899193761E+02   -0.11808E-02   -0.60097E-03    12   0.768E-01    0.615E+00
DAV:   6    -0.148236994071E+02    0.46622E+00   -0.36356E+00    12   0.186E+01    0.351E+00
DAV:   7    -0.147229862382E+02    0.10071E+00   -0.57723E-01    18   0.782E+00    0.187E+00
DAV:   8    -0.146888623570E+02    0.34124E-01   -0.12153E-01    12   0.386E+00    0.354E-01
DAV:   9    -0.146894442467E+02   -0.58189E-03   -0.18638E-02    18   0.130E+00    0.159E-01
DAV:  10    -0.146898345993E+02   -0.39035E-03   -0.29007E-03    12   0.559E-01    0.349E-02
DAV:  11    -0.146907869258E+02   -0.95233E-03   -0.24248E-04     6   0.187E-01    0.159E-02
DAV:  12    -0.146910295727E+02   -0.24265E-03   -0.81263E-05     6   0.853E-02    0.925E-03
DAV:  13    -0.146911150690E+02   -0.85496E-04   -0.43040E-05     6   0.710E-02
   1 F= -.14691115E+02 E0= -.14691115E+02  d E =0.344033E-11
Mon Mar 26 14:00:25 AEDT 2018

However, it ended with error:

Traceback (most recent call last):
  File "script.py", line 17, in <module>
    print('energy = {0} eV'.format(co.get_potential_energy()))
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/atoms.py", line 684, in get_potential_energy
    energy = self._calc.get_potential_energy(self)
  File "/home/c3289/kitchin-python/vasp/vasp/vasp.py", line 41, in inner
    return func(self, *args, **kwargs)
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/calculators/calculator.py", line 441, in get_potential_energy
    energy = self.get_property('energy', atoms)
  File "/home/c3289/kitchin-python/vasp/vasp/vasp.py", line 41, in inner
    return func(self, *args, **kwargs)
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/calculators/calculator.py", line 498, in get_property
    'calculation'.format(name))
ase.calculators.calculator.PropertyNotImplementedError: energy not present in this calculation

I thought it was came from the NPROS did not refer to the right called cpu numbers, so I commented lines 110-114, add chdir and NPROS =4, as below:

if NPROCS == 1:
                # no question. running in serial.
                # vaspcmd = VASPRC['vasp.executable.serial']
                # log.debug('NPROCS = 1. running in serial')
                # exitcode = os.system(vaspcmd)
                # return exitcode
            # else:
                # vanilla MPI run. multiprocessing does not work on more
                # than one node, and you must specify in VASPRC to use it
                if (VASPRC['queue.nodes'] > 1 or
                    (VASPRC['queue.nodes'] == 1 and
                     VASPRC['queue.ppn'] > 1 and
                     (VASPRC['multiprocessing.cores_per_process'] ==
                      'None'))):
                    os.chdir(self.directory)
                    NPROCS =4
                    s = 'queue.nodes = {0}'.format(VASPRC['queue.nodes'])
                    log.debug(s)
                    log.debug('queue.ppn = {0}'.format(VASPRC['queue.ppn']))
                    mpc = VASPRC['multiprocessing.cores_per_process']
                    log.debug('multiprocessing.cores_per_process'
                              '= {0}'.format(mpc))
                    log.debug('running vanilla MPI job')

                    log.debug('MPI NPROCS = {}'.format(NPROCS))
                    vaspcmd = VASPRC['vasp.executable.parallel']
                    parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd)
                    exitcode = os.system(parcmd)
                    return exitcode

From the output, I could make sure that VASP were parallel running, as:

 running on    4 total cores
 distrk:  each k-point on    4 cores,    1 groups
 distr:  one band on    1 cores,    4 groups
 using from now: INCAR 

However, it still caused the error as:

Traceback (most recent call last):
  File "script.py", line 17, in <module>
    print('energy = {0} eV'.format(co.get_potential_energy()))
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/atoms.py", line 684, in get_potential_energy
    energy = self._calc.get_potential_energy(self)
  File "/home/c3289/kitchin-python/vasp/vasp/vasp.py", line 41, in inner
    return func(self, *args, **kwargs)
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/calculators/calculator.py", line 441, in get_potential_energy
    energy = self.get_property('energy', atoms)
  File "/home/c3289/kitchin-python/vasp/vasp/vasp.py", line 41, in inner
    return func(self, *args, **kwargs)
  File "/cm/software/apps/python/3.5.3/lib/python3.5/site-packages/ase/calculators/calculator.py", line 498, in get_property
    'calculation'.format(name))
ase.calculators.calculator.PropertyNotImplementedError: energy not present in this calculation

Can any one give me some suggestions on this problem?

brach python3 : write_incar() function treat string a list

Newbie alert!
Brach: python3 produce INCAR like

ENCUT = 500
PREC = A c c u r a t e
LWAVE = .FALSE.
ISTART = 0
EDIFF = 1e-06
ALGO = V e r y F a s t

which should be PREC=Accurate and ALGO=VeryFast

changing
'''# elif isinstance(val, list) or isinstance(val, tuple):
elif hasattr(val, 'iter'):
val = ' '.join(str(x) for x in val)
f.write(f'{key} = {val}\n')'''

To
'''
elif isinstance(val, list) or isinstance(val, tuple):
val = ' '.join(str(x) for x in val)
f.write(f'{key} = {val}\n')'''

seems to solve the problem.

Issue with get_elapsed_time in getters.py

I am working on a computer that has some sort of profiling turned on for VASP. As a result, the OUTCAR always has a few hundred lines of extra timing information at the end. When Vasp goes to parse the OUTCAR, it looks for a certain regex 8 line for the end and does not find it (which is fine). The issue is that the regex search returns None, not the expected output from a successful search, which causes the next line to fail.

The key bit of code in get_elapsed_time in getters.py currently reads:

# fragile but fast.
m = re.search(regexp, lines[-8]) 

time = m.groupdict().get('time', None)   # this line causes crash for non-standard OUTCAR

I suggest this be changed to read:

# fragile but fast.
m = re.search(regexp, lines[-8])

if m is not None:
	time = m.groupdict().get('time', None)
	if time is not None:
		return float(time)
	else:
		return None
else:
    return None

How to set up vasp on a cluster

Dear John,

I am going to setup the code on a cluster (Redhat Linux 2 with SLURM as the job manager), where VASP is already installed as a module. The PATH and PYTHONPATH are also set in .bashrc as instructed.

I am wondering how to configure the code in details? I noticed that it might need to change the directories of VASP in the vasprc.py file. Though I used to try it on my mac and poped up many error messages...

Thanks for your kind helps,

Zezhong

Error: cannot import name 'Vasp' from 'vasp'

Hi,

I am sure I have done something wrong here, but I cannot seem to get the vasp library to run. I have defined the python and general paths as well as the potential directory.

when trying to import vasp import vasp I get the error

File "/OneDrive/pyCharm/VASPjobs/jupyterNotebooks/test.py", line 1, in
import vasp
File "
/pycharm-2020.2.3/plugins/python/helpers/pydev/_pydev_bundle/pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
File "/gitRepos/vasp_kitchin/vasp/init.py", line 1, in
from vasp import Vasp
ImportError: cannot import name 'Vasp' from 'vasp' (
/gitRepos/vasp_kitchin/vasp/init.py) <

I don't really know why this is happening, but to me it looks like the error is caused by a circular refrence?

  • import vasp calls init.py
  • init.py calls vasp.py
  • vasp.py calls vasp_core.py
  • vasp_core.py calls vasp.py

I am sure that I got it wrong, otherwise this would be a serious issue, but anyways, I cannot get the library to run and would be happy for any input.

In my .bashrc I defined:

export PYTHONPATH=/gitRepos/vasp_kitchin:$PYTHONPATH
export JUPYTER_PATH=
/gitRepos/vasp_kitchin:$JUPYTER_PATH
export PATH=/gitRepos/vasp_kitchin/bin:$PATH
export VASP_PP_PATH=
/VASP_5_4_4/mypps

I run Python 3.7 and tested this within Jupyter and PyCharm.

jasp vs vaspy on gilgamesh

Can vasp handle jobs previously run by jasp? If so, I think there's a server implementation issue on gilgamesh.

This works:

from ase import Atoms, Atom
from jasp import *

with jasp('~/dft-book/molecules/simple-co') as calc:
    atoms = calc.get_atoms()

This doesn't:

from ase import Atoms, Atom
from vasp import Vasp

print(Vasp.default_parameters) # this works.

calc = Vasp('~/dft-book/molecules/simple-co') # breaks here
atoms = calc.get_atoms()

Trace:

Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 45, in inner
    return func(self, *args, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp_core.py", line 242, in __init__
    str(label), atoms)
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/ase-s16/ase/calculators/calculator.py", line 513, in __init__
    atoms, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/ase-s16/ase/calculators/calculator.py", line 184, in __init__
    self.read(restart)  # read parameters, atoms and results
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/readers.py", line 322, in read
    atoms = self.read_atoms()
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/opt/kitchingroup/vasp-5.3.5/vaspy/vasp/readers.py", line 249, in read_atoms
    atoms.positions = xatoms.positions[resort]
AttributeError: 'NoneType' object has no attribute 'positions'

"IndexError: list index out of range" when reading potcar

I want to read an already finished calculation in the current directory:

$ cat a.py 
from vasp import Vasp
calc = Vasp('.')
$ python a.py
Unhandled exception in Vasp
Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 208, in read_potcar
    [potcar.split() for potcar in potcars]]
IndexError: list index out of range
Unhandled exception in Vasp
Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 283, in read
    self.parameters.update(self.read_potcar())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 208, in read_potcar
    [potcar.split() for potcar in potcars]]
IndexError: list index out of range
Unhandled exception in Vasp
Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/certik/ext/miniconda2/envs/ase/lib/python2.7/site-packages/ase/calculators/calculator.py", line 260, in __init__
    self.read(restart)  # read parameters, atoms and results
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 283, in read
    self.parameters.update(self.read_potcar())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 208, in read_potcar
    [potcar.split() for potcar in potcars]]
IndexError: list index out of range
Unhandled exception in Vasp
Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/certik/ext/miniconda2/envs/ase/lib/python2.7/site-packages/ase/calculators/calculator.py", line 594, in __init__
    atoms, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/certik/ext/miniconda2/envs/ase/lib/python2.7/site-packages/ase/calculators/calculator.py", line 260, in __init__
    self.read(restart)  # read parameters, atoms and results
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 283, in read
    self.parameters.update(self.read_potcar())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 208, in read_potcar
    [potcar.split() for potcar in potcars]]
IndexError: list index out of range
Traceback (most recent call last):
  File "a.py", line 2, in <module>
    calc = Vasp('.')
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 45, in inner
  File "build/bdist.linux-x86_64/egg/vasp/vasp_core.py", line 247, in __init__
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
  File "/home/certik/ext/miniconda2/envs/ase/lib/python2.7/site-packages/ase/calculators/calculator.py", line 594, in __init__
    atoms, **kwargs)
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
  File "/home/certik/ext/miniconda2/envs/ase/lib/python2.7/site-packages/ase/calculators/calculator.py", line 260, in __init__
    self.read(restart)  # read parameters, atoms and results
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 283, in read
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 51, in inner
  File "build/bdist.linux-x86_64/egg/vasp/vasp.py", line 48, in inner
  File "build/bdist.linux-x86_64/egg/vasp/readers.py", line 208, in read_potcar
IndexError: list index out of range

I am using Vasp 5.3.5. Unfortunately I can't post the actual output files.

Error executing 'qsub'

Thanks first for the nice module you wrote, I really appreciate the way it handle job queuings.

I encountered a problem trying to use it on our cluster, seems like the whitespaces in cmdlist is not handled as expected with subprocess modoule.

I tested this script from README.md and made a little modification

from ase import Atoms, Atom
from vasp import Vasp
from vasp.vasprc import VASPRC

VASPRC['mode'] = 'NONE'
VASPRC['scheduler'] = 'SGE'
VASPRC['queue.command'] = 'qsub'
VASPRC['queue.q'] = 'tw'
VASPRC['queue.pe'] = 'mpi'
VASPRC['queue.nprocs'] = '12'
VASPRC['queue.options'] = ''

co = Atoms([Atom('C', [0, 0, 0]),
            Atom('O', [1.2, 0, 0])],
           cell=(6., 6., 6.))
print co
calc = Vasp('~/simple-co',  # output dir
            xc='pbe',    # the exchange-correlation functional
            nbands=6,    # number of bands
            encut=350,   # planewave cutoff
            ismear=1,    # Methfessel-Paxton smearing
            sigma=0.01,  # very small smearing factor for a molecule
            atoms=co)

print('energy = {0} eV'.format(co.get_potential_energy()))

will give this

Exception: something went wrong in qsub:

qsub: ERROR! invalid option argument "-q tw"

Replacing whitespaces with seperated arguments fixed the problem.

The test is done with @prtkm Prateek's fork for SGE since that's the only Queuing system I get access to, but I think the code for PBS is also affected.


I also checked the subprocess documentation and it uses shell=True whenever a whitespace appears in a argument string, which is not present in the runner.py code.

I also did some validation in ipython

In [1]: import subprocess

In [2]: subprocess.Popen('echo 123')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
...( I omitted some error log here)...
FileNotFoundError: [Errno 2] No such file or directory: 'echo 123'

In [6]: subprocess.Popen(['echo', '123'])
123
Out[6]: <subprocess.Popen at 0x7f219b31e690>

In [7]: subprocess.Popen(['echo 123'],shell=True)
Out[7]: <subprocess.Popen at 0x7f219a781bd0>

123

I'm not sure if it's a real problem or bug, please kindly tell me if I missed something simple.

Updated approach for bader

Hi John,

I was just reading the code you pushed recently in bader.py. I recently updated the way to do it in my fork of jasp, which I feel seems to work a little better. In the old approach, by saving the charges in atom.charge, they are returned by atoms.get_initial_charges() and not atoms.get_charges() as they should. This causes problems when you write an atoms row in the database, where the charges are stored as 'initial_charges' (which is confusing!).

Below is the updated code I have for bader in jasp. It now returns the calculated charges with atoms.get_charges(). It might be useful to use a similar approach in the new vasp wrapper.

def bader(self, cmd=None, ref=False, verbose=False, overwrite=False):

    '''
    Performs bader analysis for a calculation

    Follows defaults unless full shell command is specified

    Does not overwrite existing files if overwrite=False
    If ref = True, tries to reference the charge density to
    the sum of AECCAR0 and AECCAR2

    Requires the bader.pl (and chgsum.pl) script to be in the system PATH
    '''

    if 'ACF.dat' in os.listdir('./') and not overwrite:
        self._get_calculated_charges()
        return

    if cmd is None:
        if ref:
            self.chgsum()
            cmdlist = ['bader',
                       'CHGCAR',
                       '-ref',
                       'CHGCAR_sum']
        else:
            cmdlist = ['bader',
                       'CHGCAR']
    elif type(cmd) is str:
        cmdlist = cmd.split()
    elif type(cmd) is list:
        cmdlist = cmd

    p = Popen(cmdlist, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    out, err = p.communicate()
    if out == '' or err != '':
        raise Exception('Cannot perform Bader:\n\n{0}'.format(err))
    elif verbose:
        print('Bader completed for {0}'.format(self.vaspdir))

    # Now store calculated charges
    self._get_calculated_charges()

Vasp.bader = bader


def _get_calculated_charges(self,
                            atoms=None,
                            fileobj='ACF.dat',
                            displacement=1e-4):

    """Calculate the charges from the fileobj.
    This is a modified version of the attach_charges function in
    ase.io.bader to work better with VASP.
    Does not require the atom positions to be in Bohr and references
    the charge to the ZVAL in the POTCAR
    """

    if isinstance(fileobj, str):
        try:
            fileobj = open(fileobj)
            f_open = True
        except(IOError):
            return None

    if atoms is None:
        atoms = self.get_atoms()

    # Get the sorting and resorting lists
    sort = self.sort
    resort = self.resort

    # First get a dictionary of ZVALS from the pseudopotentials
    LOP = self.get_pseudopotentials()
    ppp = os.environ['VASP_PP_PATH']

    zval = {}
    for sym, ppath, hash in LOP:
        fullpath = ppp + ppath
        z = get_ZVAL(fullpath)
        zval[sym] = z

    # Get sorted symbols and positions according to POSCAR and ACF.dat
    symbols = np.array(atoms.get_chemical_symbols())[sort]
    positions = atoms.get_positions()[sort]

    charges = []
    sep = '---------------'
    i = 0  # Counter for the lines
    k = 0  # Counter of sep
    assume6columns = False
    for line in fileobj:
        if line[0] == '\n':  # check if there is an empty line in the
            i -= 1           # head of ACF.dat file
        if i == 0:
            headings = line
            if 'BADER' in headings.split():
                j = headings.split().index('BADER')
            elif 'CHARGE' in headings.split():
                j = headings.split().index('CHARGE')
            else:
                print('Can\'t find keyword "BADER" or "CHARGE".' \
                      + ' Assuming the ACF.dat file has 6 columns.')
                j = 4
                assume6columns = True
        if sep in line:  # Stop at last seperator line
            if k == 1:
                break
            k += 1
        if not i > 1:
            pass
        else:
            words = line.split()
            if assume6columns is True:
                if len(words) != 6:
                    raise IOError('Number of columns in ACF file incorrect!\n'
                                  'Check that Bader program version >= 0.25')

            sym = symbols[int(words[0]) - 1]
            charges.append(zval[sym] - float(words[j]))

            if displacement is not None:
                # check if the atom positions match
                xyz = np.array([float(w) for w in words[1:4]])
                assert np.linalg.norm(positions[int(words[0]) - 1] - xyz) < displacement
        i += 1

    if f_open:
        fileobj.close()

    # Now attach the resorted charges to the atom
    charges = np.array(charges)[resort]
    self._calculated_charges = charges

Vasp._get_calculated_charges = _get_calculated_charges


def get_charges(self, atoms=None):
    '''
    Returns a list of cached charges from a previous
    call to bader(). Useful for storing the charges to
    a database outside the context manager.
    '''

    if atoms is None:
        atoms = self.get_atoms()

    if hasattr(self, '_calculated_charges'):
        return self._calculated_charges
    else:
        return None

Vasp.get_charges = get_charges


def get_property(self, name, atoms=None, allow_calculation=True):
    """A function meant to mimic the get_property() function
    already implemented for non-VASP calculators in ASE.
    This function is required for proper usage of the ASE database
    the way it is currently written.
    """

    if atoms is None:
        atoms = self.get_atoms()

    if name == 'energy':
        return atoms.get_potential_energy()

    elif name == 'forces':
        return atoms.get_forces()

    elif name == 'stress':
        return atoms.get_stress()

    elif name == 'dipole':
        return atoms.get_dipole_moment()

    elif name == 'magmom' and hasattr(self, 'magnetic_moment'):
        return atoms.get_magnetic_moment()

    elif name == 'magmoms':
        return atoms.get_magnetic_moments()

    elif name == 'charges':
        return atoms.get_charges()

    else:
        raise NotImplementedError

Vasp.get_property = get_property

vaspy and python3

Hi John,

Have you tried running vaspy with python3? I seem to be getting this error on the initial import, but am not sure why that is. Any ideas?

from vasp import Vasp
Traceback (most recent call last):
File "", line 1, in
File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/init.py", line 1, in
from vasp import Vasp
ImportError: cannot import name 'Vasp'

Updating atoms in a cloned calculation?

How do you update the atoms in a cloned calculation? For example, I would like to clone a relaxed structure, fix the positions of most of the atoms (e.g., the slab), then calculate the vibrational spectrum of the remaining atoms (e.g., the adsorbates). I have tried a number of different things, but vasp never writes a new, updated POSCAR file, instead it uses the original CONTCAR from the previous calculation.

For example, this does not work:

from vasp import Vasp
from ase.constraints import FixAtoms

calc = Vasp("oldCalc")
calc.clone("newCalc")

# Freeze all of the atoms in the slab
slab = calc.get_atoms()
inSlab = []
for atom in slab:
    inSlab.append(atom.index)
theConstraints = FixAtoms(indices = inSlab)
slab.set_constraint(theConstraints)

# Update the calculator with the constrained slab
calc.atoms = slab

name = 'vasp.executable.serial'
calc.VASPRC[name] = 'runvasp.py'
calc.set(nsw = 5)   # This just forces a recalculation

calc.calculate()    # This initiates a calculation on the _unconstrained_ slab / original CONTCAR

Thanks,

Melissa

PropertyNotImplementedError in get_property

Hi, I am trying to use vasp compiler with ase v3.13.0.
But, I always meet PropertyNotImplementedError in get_property for any calculation like get_stress(), get_potential(), get_forces(), ....etc.

I tried ase.calculators.vasp, and they work well.
Can you help me find the problem?

Unhandled exception in Vasp
Traceback (most recent call last):
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/vasp/vasp/vasp.py", line 48, in inner
return func(self, *args, **kwargs)
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/ase/calculators/calculator.py", line 472, in get_property
raise PropertyNotImplementedError
PropertyNotImplementedError
Unhandled exception in Vasp
Traceback (most recent call last):
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/vasp/vasp/vasp.py", line 48, in inner
return func(self, *args, **kwargs)
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/ase/calculators/calculator.py", line 432, in get_stress
return self.get_property('stress', atoms)
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/vasp/vasp/vasp.py", line 51, in inner
return self.exception_handler(self, *sys.exc_info())
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/vasp/vasp/vasp.py", line 48, in inner
return func(self, *args, **kwargs)
File "/home/yoop/sw/anaconda2/lib/python2.7/site-packages/ase/calculators/calculator.py", line 472, in get_property
raise PropertyNotImplementedError
PropertyNotImplementedError

invalid syntax for 'forces'

Hi,

I am new to the python version of vasp and excited to know it works with ASE. However, after installed the ASE and vasp, all the calculations I have tested shown there are syntax error for the 'forces' in vasp_core.py. Other calucations in ASE are working fine. I am wondering where went wrong during my installation.

A test sample is attached below

from vasp import Vasp
from ase import Atom, Atoms
import logging

bond_lengths = [1.05, 1.1, 1.15, 1.2, 1.25]

ATOMS = [Atoms([Atom('C', [0, 0, 0]),
                Atom('O', [d, 0, 0])],
               cell=(6, 6, 6))
         for d in bond_lengths]

calcs = [Vasp('~/dft-book-new-vasp/molecules/co-{0}'.format(d),  # output dir
                xc='PBE',
                nbands=6,
                encut=350,
                ismear=1,
                sigma=0.01, debug=True,
                atoms=atoms)
         for d, atoms in zip(bond_lengths, ATOMS)]

energies = [atoms.get_potential_energy() for atoms in ATOMS]

print(energies)

File "/usr/local/lib/python2.7/site-packages/vasp-0.1-py2.7.egg/vasp/vasp_core.py", line 867
forces=atoms.get_forces()[self.resort]))
^
SyntaxError: invalid syntax

Thanks a lot for your helps!

Cheers,
Zezhong

Atom sorting issue

There seems to be a sorting related issue with the following example:

from vasp import Vasp
from ase.lattice.surface import fcc111

# Create surface image
atoms = fcc111('Cu', size=(3, 3, 5), vacuum=6.0, a=3.628)
atoms[40].symbol = 'Pd'

calc = Vasp('impurity-calc',
        xc='PBE',
        kpts=[2, 2, 1],
        encut=250,
        atoms=atoms)
calc.write_input()

Running the block twice results in the following error:

Traceback (most recent call last):
  File "<stdin>", line 13, in <module>
  File "/home-research/jboes/python/vasp/vasp/vasp.py", line 44, in inner
    return func(self, *args, **kwargs)
  File "/home-research/jboes/python/vasp/vasp/vasp_core.py", line 237, in __init__
    str(label), atoms)
  File "/home-research/jboes/python/vasp/vasp/vasp.py", line 50, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home-research/jboes/python/vasp/vasp/vasp.py", line 47, in inner
    return func(self, *args, **kwargs)
  File "/home-research/jboes/python/ase/ase/calculators/calculator.py", line 513, in __init__
    atoms, **kwargs)
  File "/home-research/jboes/python/vasp/vasp/vasp.py", line 50, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home-research/jboes/python/vasp/vasp/vasp.py", line 47, in inner
    return func(self, *args, **kwargs)
  File "/home-research/jboes/python/ase/ase/calculators/calculator.py", line 207, in __init__
    raise RuntimeError('Atoms not compatible with file')
RuntimeError: Atoms not compatible with file

The Pd in VASPSUM ends up as index 43, rather than 40 as assigned in the code block.

kpoints with gamma=True

Hi John,

When I try to do a calculation with gamma=True, vaspy stumbles with the error,

Traceback (most recent call last):
  File "<stdin>", line 35, in <module>
  File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/vasp.py", line 45, in inner
    return func(self, *args, **kwargs)
  File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/writers.py", line 26, in write_input
    self.write_kpoints()
  File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/vasp.py", line 45, in inner
    return func(self, *args, **kwargs)
  File "/afs/crc.nd.edu/user/p/pmehta1/vasp/vasp/writers.py", line 279, in write_kpoints
    if p.get('gamma', None) and len(p.get('gamma')) == 3:
TypeError: object of type 'bool' has no len()

This is because it is trying to get the length of True and failing.

Alternatively, I could pass gamma=[0, 0, 0] and the calculation will submit, but when reading the results the parameters on file think gamma=True when the passed parameters have gamma=[0,0,0] leading to unwanted resubmission.

use 'vasp' to do Postprocessing on completed VASP jobs

can I use 'vasp' package to do postprocessing on my finished VASP jobs.

I would like to use a vasp function like "get_ados" on my already available "vasprun.xml". How can I do this?

There are also other "get_" functions in getters.py. Is it possible to use these functions from completed VASP jobs' OUTCAR or vasprun.xml?

Running without Torque

Thank you very much for making this available. It looks like a very worthy successor to jasp and a great complement to your book.

Like zezhong-zhang from a few days ago, I am trying to get this running, ideally in parallel, on a Mac, so I do not have Torque running a queue. I can get it to run serially by changing one line in vasprc.py:

vs = '/Users/mah/VASP/src/vaspSol.5.4.1/bin/vasp_std'
where the path is to my installation of vasp. I also added "Vasp.vasprc(mode='run')" to my script (the suggestion from your answer to zezhong-zhang).

Is there any way for me to run vasp in parallel without Torque? When I use ASE, I just put the following in runvasp.py:

#!/usr/bin/env python
import os

parallel_vasp = '/Users/mah/VASP/src/vaspSol.5.4.1/bin/vasp_std'

parcmd = 'mpirun -np 4 /Users/mah/VASP/src/vaspSol.5.4.1/bin/vasp_std >> mahVASP.out'
exitcode = os.system(parcmd)

My guess is that I am missing something very simple, so thank you for your help.

Melissa

atoms_sorted issue

I am trying to run your VASP interface with ASE and am getting the following issue: AttributeError: 'Vasp' object has no attribute 'atoms_sorted'. The traceback is shown below. I am using the newest version of ASE, so perhaps this is a recent change that conflicts with your interface? I could also just be doing something wrong since I haven't used your interface before. Any suggestions?

Traceback (most recent call last):
  File "sp_energy.py", line 12, in <module>
    e = isobutane.get_potential_energy()
  File "/home/asr731/software/ase/ase/atoms.py", line 682, in get_potential_energy
    energy = self._calc.get_potential_energy(self)
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/asr731/software/ase/ase/calculators/calculator.py", line 441, in get_potential_energy
    energy = self.get_property('energy', atoms)
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/asr731/software/ase/ase/calculators/calculator.py", line 486, in get_property
    self.calculate(atoms, [name], system_changes)
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/asr731/software/kitchin_vasp/vasp/runner.py", line 94, in calculate
    self.write_input(atoms, properties, system_changes)
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/asr731/software/kitchin_vasp/vasp/writers.py", line 23, in write_input
    self.write_poscar()
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 51, in inner
    return self.exception_handler(self, *sys.exc_info())
  File "/home/asr731/software/kitchin_vasp/vasp/vasp.py", line 48, in inner
    return func(self, *args, **kwargs)
  File "/home/asr731/software/kitchin_vasp/vasp/writers.py", line 150, in write_poscar
    self.atoms_sorted,
AttributeError: 'Vasp' object has no attribute 'atoms_sorted'

getters/ados s p d, or s px py pz

in my vasp.xml, partial dos is reported as:

   <field>energy</field>
     <field>    s</field>
     <field>   py</field>
     <field>   pz</field>
     <field>   px</field>
     <field>  dxy</field>
     <field>  dyz</field>
     <field>  dz2</field>
     <field>  dxz</field>
     <field>x2-y2</field>
     <set>

so the xml parser in getters/ados returns a list of lists as
i.e. [[-22.0163, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [-21.9061, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ...
thus when you call ados, with orbital p, I only see px, and worse, when I ask for d, I get py

Package Install Problems

I installed vasp in a cluster by first run setup.py, followed by clone the repo to ~/jkitchin-python. However, when I call 'from vasp import Vasp', a error occured as:
Traceback (most recent call last): File "script.py", line 2, in <module> from vasp import Vasp File "/home/c3289/kitchin-python/vasp/vasp.py", line 24, in <module> import writers File "/home/c3289/kitchin-python/vasp/writers.py", line 17, in <module> def write_input(self, atoms=None, properties=None, system_changes=None): File "/home/c3289/kitchin-python/vasp/monkeypatch.py", line 16, in decorato r func.__doc__ += s.format(f=func) AttributeError: 'function' object has no attribute 'func_code'
Does this means I made mistakes in install this package?

Thanks.

Cannot read vibrational modes with NWRITE=3

vasp/vasp/vib.py

Lines 53 to 62 in 6c73e7f

if hasattr(atoms, 'constraints') and self.parameters['ibrion'] == 5:
# count how many modes to get.
NMODES = 0
f = open(os.path.join(self.directory, 'OUTCAR'))
for line in f:
if ('f' in line and 'THz' in line and 'cm-1' in line):
NMODES += 1
f.close()
else:
NMODES = 3 * len(atoms)

The current code will count the modes twice if NWRITE = 3

We need to add something like

if self.parameters.get('nwrite') == 3:
    NMODES = NMODES // 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.