Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""This module defines an ASE interface to ABINIT.
3http://www.abinit.org/
4"""
6import re
8import ase.io.abinit as io
9from ase.calculators.calculator import FileIOCalculator
10from subprocess import check_output
13def get_abinit_version(command):
14 txt = check_output([command, '--version']).decode('ascii')
15 # This allows trailing stuff like betas, rc and so
16 m = re.match(r'\s*(\d\.\d\.\d)', txt)
17 if m is None:
18 raise RuntimeError('Cannot recognize abinit version. '
19 'Start of output: {}'
20 .format(txt[:40]))
21 return m.group(1)
24class Abinit(FileIOCalculator):
25 """Class for doing ABINIT calculations.
27 The default parameters are very close to those that the ABINIT
28 Fortran code would use. These are the exceptions::
30 calc = Abinit(label='abinit', xc='LDA', ecut=400, toldfe=1e-5)
31 """
33 implemented_properties = ['energy', 'forces', 'stress', 'magmom']
34 ignored_changes = {'pbc'} # In abinit, pbc is always effectively True.
35 command = 'abinit < PREFIX.files > PREFIX.log'
36 discard_results_on_any_change = True
38 default_parameters = dict(
39 xc='LDA',
40 smearing=None,
41 kpts=None,
42 raw=None,
43 pps='fhi')
45 def __init__(self, restart=None,
46 ignore_bad_restart_file=FileIOCalculator._deprecated,
47 label='abinit', atoms=None, pp_paths=None,
48 v8_legacy_format=None,
49 **kwargs):
50 """Construct ABINIT-calculator object.
52 Parameters
53 ==========
54 label: str
55 Prefix to use for filenames (label.in, label.txt, ...).
56 Default is 'abinit'.
58 Examples
59 ========
60 Use default values:
62 >>> h = Atoms('H', calculator=Abinit(ecut=200, toldfe=0.001))
63 >>> h.center(vacuum=3.0)
64 >>> e = h.get_potential_energy()
66 """
68 self.v8_legacy_format = v8_legacy_format
69 self.pp_paths = pp_paths
71 FileIOCalculator.__init__(self, restart, ignore_bad_restart_file,
72 label, atoms, **kwargs)
74 def write_input(self, atoms, properties, system_changes):
75 """Write input parameters to files-file."""
76 io.write_all_inputs(
77 atoms, properties, parameters=self.parameters,
78 pp_paths=self.pp_paths,
79 label=self.label, v8_legacy_format=self.v8_legacy_format)
81 def read(self, label):
82 """Read results from ABINIT's text-output file."""
83 # XXX I think we should redo the concept of 'restarting'.
84 # It makes sense to load a previous calculation as
85 #
86 # * static, calculator-independent results
87 # * an actual calculator capable of calculating
88 #
89 # Either of which is simpler than our current mechanism which
90 # implies both at the same time. Moreover, we don't need
91 # something like calc.read(label).
92 #
93 # What we need for these two purposes is
94 #
95 # * calc = MyCalculator.read(basefile)
96 # (or maybe it should return Atoms with calc attached)
97 # * results = read_results(basefile, format='abinit')
98 #
99 # where basefile determines the file tree.
100 FileIOCalculator.read(self, label)
101 self.atoms, self.parameters = io.read_ase_and_abinit_inputs(self.label)
102 self.results = io.read_results(self.label, self._output_filename())
104 def _output_filename(self):
105 if self.v8_legacy_format:
106 ext = '.txt'
107 else:
108 ext = '.abo'
109 return self.label + ext
111 def read_results(self):
112 self.results = io.read_results(self.label, self._output_filename())
114 def get_number_of_iterations(self):
115 return self.results['niter']
117 def get_electronic_temperature(self):
118 return self.results['width']
120 def get_number_of_electrons(self):
121 return self.results['nelect']
123 def get_number_of_bands(self):
124 return self.results['nbands']
126 def get_k_point_weights(self):
127 return self.results['kpoint_weights']
129 def get_bz_k_points(self):
130 raise NotImplementedError
132 def get_ibz_k_points(self):
133 return self.results['ibz_kpoints']
135 def get_spin_polarized(self):
136 return self.results['eigenvalues'].shape[0] == 2
138 def get_number_of_spins(self):
139 return len(self.results['eigenvalues'])
141 def get_fermi_level(self):
142 return self.results['fermilevel']
144 def get_eigenvalues(self, kpt=0, spin=0):
145 return self.results['eigenvalues'][spin, kpt]
147 def get_occupations(self, kpt=0, spin=0):
148 raise NotImplementedError