1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
"""This module defines an ASE interface to NWchem
https://nwchemgit.github.io
"""
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
class NWChem(FileIOCalculator):
implemented_properties = ['energy', 'forces', 'stress', 'dipole']
command = 'nwchem PREFIX.nwi > PREFIX.nwo'
accepts_bandpath_keyword = True
discard_results_on_any_change = True
def __init__(self, restart=None,
ignore_bad_restart_file=FileIOCalculator._deprecated,
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 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 = io.read(self.label + '.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)
|