Source code for ase.calculators.nwchem

"""This module defines an ASE interface to NWchem
import os
import numpy as np

from ase import io
from ase.units import Hartree
from ase.calculators.calculator import FileIOCalculator
from ase.spectrum.band_structure import BandStructure

[docs]class NWChem(FileIOCalculator): implemented_properties = ['energy', 'forces', 'stress', 'dipole'] command = 'nwchem PREFIX.nwi > PREFIX.nwo' accepts_bandpath_keyword = True def __init__(self, restart=None, ignore_bad_restart_file=False, label='nwchem', atoms=None, command=None, **kwargs): """ NWChem keywords are specified using (potentially nested) dictionaries. Consider the following input file block: >>> dft >>> odft >>> mult 2 >>> convergence energy 1e-9 density 1e-7 gradient 5e-6 >>> end This can be generated by the NWChem calculator by using the following settings: >>> calc = NWChem(dft={'odft': None, >>> 'mult': 2, >>> 'convergence': {'energy': 1e-9, >>> 'density': 1e-7, >>> 'gradient': 5e-6, >>> }, >>> }, >>> ) In addition, the calculator supports several special keywords: theory: str Which NWChem module should be used to calculate the energies and forces. Supported values are ``'dft'``, ``'scf'``, ``'mp2'``, ``'ccsd'``, ``'tce'``, ``'tddft'``, ``'pspw'``, ``'band'``, and ``'paw'``. If not provided, the calculator will attempt to guess which theory to use based on the keywords provided by the user. xc: str The exchange-correlation functional to use. Only relevant for DFT calculations. task: str What type of calculation is to be performed, e.g. ``'energy'``, ``'gradient'``, ``'optimize'``, etc. When using ``'SocketIOCalculator'``, ``task`` should be set to ``'optimize'``. In most other circumstances, ``task`` should not be set manually. basis: str or dict Which basis set to use for gaussian-type orbital calculations. Set to a string to use the same basis for all elements. To use a different basis for different elements, provide a dict of the form: >>> calc = NWChem(..., >>> basis={'O': '3-21G', >>> 'Si': '6-31g'}) basispar: str Additional keywords to put in the NWChem ``basis`` block, e.g. ``'rel'`` for relativistic bases. symmetry: int or str The point group (for gaussian-type orbital calculations) or space group (for plane-wave calculations) of the system. Supports both group names (e.g. ``'c2v'``, ``'Fm3m'``) and numbers (e.g. ``225``). autosym: bool Whether NWChem should automatically determine the symmetry of the structure (defaults to ``False``). center: bool Whether NWChem should automatically center the structure (defaults to ``False``). Enable at your own risk. autoz: bool Whether NWChem should automatically construct a Z-matrix for your molecular system (defaults to ``False``). geompar: str Additional keywords to put in the NWChem `geometry` block, e.g. ``'nucleus finite'`` for gaussian-shaped nuclear charges. Do not set ``'autosym'``, ``'center'``, or ``'autoz'`` in this way; instead, use the appropriate keyword described above for these settings. set: dict Used to manually create or modify entries in the NWChem rtdb. For example, the following settings enable pseudopotential filtering for plane-wave calculations: >>> set nwpw:kbpp_ray .true. >>> set nwpw:kbpp_filter .true. These settings are generated by the NWChem calculator by passing the arguments: >>> calc = NWChem(..., >>> set={'nwpw:kbpp_ray': True, >>> 'nwpw:kbpp_filter': True}) kpts: (int, int, int), or dict Indicates which k-point mesh to use. Supported syntax is similar to that of GPAW. Implies ``theory='band'``. bandpath: BandPath object The band path to use for a band structure calculation. Implies ``theory='band'``. """ FileIOCalculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, command, **kwargs) self.calc = None def set(self, **kwargs): changed_parameters = FileIOCalculator.set(self, **kwargs) if changed_parameters: self.reset() def write_input(self, atoms, properties=None, system_changes=None): FileIOCalculator.write_input(self, atoms, properties, system_changes) # Prepare perm and scratch directories perm = os.path.abspath(self.parameters.get('perm', self.label)) scratch = os.path.abspath(self.parameters.get('scratch', self.label)) os.makedirs(perm, exist_ok=True) os.makedirs(scratch, exist_ok=True) io.write(self.label + '.nwi', atoms, properties=properties, label=self.label, **self.parameters) def read_results(self): output = + '.nwo') self.calc = output.calc self.results = output.calc.results def band_structure(self): self.calculate() perm = self.parameters.get('perm', self.label) if self.calc.get_spin_polarized(): alpha = np.loadtxt(os.path.join(perm, self.label + '.alpha_band')) beta = np.loadtxt(os.path.join(perm, self.label + '.beta_band')) energies = np.array([alpha[:, 1:], beta[:, 1:]]) * Hartree else: data = np.loadtxt(os.path.join(perm, self.label + '.restricted_band')) energies = data[np.newaxis, :, 1:] * Hartree eref = self.calc.get_fermi_level() if eref is None: eref = 0. return BandStructure(self.parameters.bandpath, energies, eref)