Statistiques
| Révision :

root / ase / calculators / abinit.py @ 2

Historique | Voir | Annoter | Télécharger (21,37 ko)

1 1 tkerber
"""This module defines an ASE interface to ABINIT.
2 1 tkerber

3 1 tkerber
http://www.abinit.org/
4 1 tkerber
"""
5 1 tkerber
6 1 tkerber
import os
7 1 tkerber
from glob import glob
8 1 tkerber
from os.path import join, isfile, islink
9 1 tkerber
10 1 tkerber
import numpy as np
11 1 tkerber
12 1 tkerber
from ase.data import chemical_symbols
13 1 tkerber
from ase.data import atomic_numbers
14 1 tkerber
from ase.units import Bohr, Hartree
15 1 tkerber
16 1 tkerber
17 1 tkerber
class Abinit:
18 1 tkerber
    """Class for doing ABINIT calculations.
19 1 tkerber

20 1 tkerber
    The default parameters are very close to those that the ABINIT
21 1 tkerber
    Fortran code would use.  These are the exceptions::
22 1 tkerber

23 1 tkerber
      calc = Abinit(label='abinit', xc='LDA', pulay=5, mix=0.1)
24 1 tkerber

25 1 tkerber
    Use the set_inp method to set extra INPUT parameters::
26 1 tkerber

27 1 tkerber
      calc.set_inp('nstep', 30)
28 1 tkerber

29 1 tkerber
    """
30 1 tkerber
    def __init__(self, label='abinit', xc='LDA', kpts=None, nbands=0,
31 1 tkerber
                 width=0.04*Hartree, ecut=None, charge=0,
32 1 tkerber
                 pulay=5, mix=0.1, pps='fhi', toldfe=1.0e-6
33 1 tkerber
                 ):
34 1 tkerber
        """Construct ABINIT-calculator object.
35 1 tkerber

36 1 tkerber
        Parameters
37 1 tkerber
        ==========
38 1 tkerber
        label: str
39 1 tkerber
            Prefix to use for filenames (label.in, label.txt, ...).
40 1 tkerber
            Default is 'abinit'.
41 1 tkerber
        xc: str
42 1 tkerber
            Exchange-correlation functional.  Must be one of LDA, PBE,
43 1 tkerber
            revPBE, RPBE.
44 1 tkerber
        kpts: list of three int
45 1 tkerber
            Monkhost-Pack sampling.
46 1 tkerber
        nbands: int
47 1 tkerber
            Number of bands.
48 1 tkerber
            Default is 0.
49 1 tkerber
        width: float
50 1 tkerber
            Fermi-distribution width in eV.
51 1 tkerber
            Default is 0.04 Hartree.
52 1 tkerber
        ecut: float
53 1 tkerber
            Planewave cutoff energy in eV.
54 1 tkerber
            No default.
55 1 tkerber
        charge: float
56 1 tkerber
            Total charge of the system.
57 1 tkerber
            Default is 0.
58 1 tkerber
        pulay: int
59 1 tkerber
            Number of old densities to use for Pulay mixing.
60 1 tkerber
        mix: float
61 1 tkerber
            Mixing parameter between zero and one for density mixing.
62 1 tkerber

63 1 tkerber
        Examples
64 1 tkerber
        ========
65 1 tkerber
        Use default values:
66 1 tkerber

67 1 tkerber
        >>> h = Atoms('H', calculator=Abinit())
68 1 tkerber
        >>> h.center(vacuum=3.0)
69 1 tkerber
        >>> e = h.get_potential_energy()
70 1 tkerber

71 1 tkerber
        """
72 1 tkerber
73 1 tkerber
        if not nbands > 0:
74 1 tkerber
            raise ValueError('Number of bands (nbands) not set')
75 1 tkerber
76 1 tkerber
        if ecut is None:
77 1 tkerber
            raise ValueError('Planewave cutoff energy in eV (ecut) not set')
78 1 tkerber
79 1 tkerber
        self.label = label#################### != out
80 1 tkerber
        self.xc = xc
81 1 tkerber
        self.kpts = kpts
82 1 tkerber
        self.nbands = nbands
83 1 tkerber
        self.width = width
84 1 tkerber
        self.ecut = ecut
85 1 tkerber
        self.charge = charge
86 1 tkerber
        self.pulay = pulay
87 1 tkerber
        self.mix = mix
88 1 tkerber
        self.pps = pps
89 1 tkerber
        self.toldfe = toldfe
90 1 tkerber
        if not pps in ['fhi', 'hgh', 'hgh.sc']:
91 1 tkerber
            raise ValueError('Unexpected PP identifier %s' % pps)
92 1 tkerber
93 1 tkerber
        self.converged = False
94 1 tkerber
        self.inp = {}
95 1 tkerber
        self.n_entries_int = 20 # integer entries per line
96 1 tkerber
        self.n_entries_float = 8 # float entries per line
97 1 tkerber
98 1 tkerber
    def update(self, atoms):
99 1 tkerber
        if (not self.converged or
100 1 tkerber
            len(self.numbers) != len(atoms) or
101 1 tkerber
            (self.numbers != atoms.get_atomic_numbers()).any()):
102 1 tkerber
            self.initialize(atoms)
103 1 tkerber
            self.calculate(atoms)
104 1 tkerber
        elif ((self.positions != atoms.get_positions()).any() or
105 1 tkerber
              (self.pbc != atoms.get_pbc()).any() or
106 1 tkerber
              (self.cell != atoms.get_cell()).any()):
107 1 tkerber
            self.calculate(atoms)
108 1 tkerber
109 1 tkerber
    def initialize(self, atoms):
110 1 tkerber
        self.numbers = atoms.get_atomic_numbers().copy()
111 1 tkerber
        self.species = []
112 1 tkerber
        for a, Z in enumerate(self.numbers):
113 1 tkerber
            if Z not in self.species:
114 1 tkerber
                self.species.append(Z)
115 1 tkerber
116 1 tkerber
        if 'ABINIT_PP_PATH' in os.environ:
117 1 tkerber
            pppaths = os.environ['ABINIT_PP_PATH'].split(':')
118 1 tkerber
        else:
119 1 tkerber
            pppaths = []
120 1 tkerber
121 1 tkerber
        self.ppp_list = []
122 1 tkerber
        if self.xc != 'LDA':
123 1 tkerber
            xcname = 'GGA'
124 1 tkerber
        else:
125 1 tkerber
            xcname = 'LDA'
126 1 tkerber
127 1 tkerber
        for Z in self.species:
128 1 tkerber
            symbol = chemical_symbols[abs(Z)]
129 1 tkerber
            number = atomic_numbers[symbol]
130 1 tkerber
131 1 tkerber
            pps = self.pps
132 1 tkerber
            if pps == 'fhi':
133 1 tkerber
                name = '%02d-%s.%s.fhi' % (number, symbol, xcname)
134 1 tkerber
            elif pps in ('hgh', 'hgh.sc'):
135 1 tkerber
                hghtemplate = '%d%s.%s.hgh' # E.g. "42mo.6.hgh"
136 1 tkerber
                # There might be multiple files with different valence
137 1 tkerber
                # electron counts, so we must choose between
138 1 tkerber
                # the ordinary and the semicore versions for some elements.
139 1 tkerber
                #
140 1 tkerber
                # Therefore we first use glob to get all relevant files,
141 1 tkerber
                # then pick the correct one afterwards.
142 1 tkerber
                name = hghtemplate % (number, symbol.lower(), '*')
143 1 tkerber
144 1 tkerber
            found = False
145 1 tkerber
            for path in pppaths:
146 1 tkerber
                if pps.startswith('hgh'):
147 1 tkerber
                    filenames = glob(join(path, name))
148 1 tkerber
                    if not filenames:
149 1 tkerber
                        continue
150 1 tkerber
                    assert len(filenames) in [0, 1, 2]
151 1 tkerber
                    if pps == 'hgh':
152 1 tkerber
                        selector = min # Lowest possible valence electron count
153 1 tkerber
                    else:
154 1 tkerber
                        assert pps == 'hgh.sc'
155 1 tkerber
                        selector = max # Semicore - highest electron count
156 1 tkerber
                    Z = selector([int(os.path.split(name)[1].split('.')[1])
157 1 tkerber
                                  for name in filenames])
158 1 tkerber
                    name = hghtemplate % (number, symbol.lower(), str(Z))
159 1 tkerber
                filename = join(path, name)
160 1 tkerber
                if isfile(filename) or islink(filename):
161 1 tkerber
                    found = True
162 1 tkerber
                    self.ppp_list.append(filename)
163 1 tkerber
                    break
164 1 tkerber
            if not found:
165 1 tkerber
                raise RuntimeError('No pseudopotential for %s!' % symbol)
166 1 tkerber
167 1 tkerber
        self.converged = False
168 1 tkerber
169 1 tkerber
    def get_potential_energy(self, atoms, force_consistent=False):
170 1 tkerber
        self.update(atoms)
171 1 tkerber
172 1 tkerber
        if force_consistent:
173 1 tkerber
            return self.efree
174 1 tkerber
        else:
175 1 tkerber
            # Energy extrapolated to zero Kelvin:
176 1 tkerber
            return  (self.etotal + self.efree) / 2
177 1 tkerber
178 1 tkerber
    def get_number_of_bands(self):
179 1 tkerber
        return self.nbands
180 1 tkerber
181 1 tkerber
    def get_kpts_info(self, kpt=0, spin=0, mode='eigenvalues'):
182 1 tkerber
        return self.read_kpts_info(kpt, spin, mode)
183 1 tkerber
184 1 tkerber
    def get_k_point_weights(self):
185 1 tkerber
        return self.get_kpts_info(kpt=0, spin=0, mode='k_point_weights')
186 1 tkerber
187 1 tkerber
    def get_bz_k_points(self):
188 1 tkerber
        raise NotImplementedError
189 1 tkerber
190 1 tkerber
    def get_ibz_k_points(self):
191 1 tkerber
        return self.get_kpts_info(kpt=0, spin=0, mode='ibz_k_points')
192 1 tkerber
193 1 tkerber
    def get_fermi_level(self):
194 1 tkerber
        return self.read_fermi()
195 1 tkerber
196 1 tkerber
    def get_eigenvalues(self, kpt=0, spin=0):
197 1 tkerber
        return self.get_kpts_info(kpt, spin, 'eigenvalues')
198 1 tkerber
199 1 tkerber
    def get_occupations(self, kpt=0, spin=0):
200 1 tkerber
        return self.get_kpts_info(kpt, spin, 'occupations')
201 1 tkerber
202 1 tkerber
    def get_forces(self, atoms):
203 1 tkerber
        self.update(atoms)
204 1 tkerber
        return self.forces.copy()
205 1 tkerber
206 1 tkerber
    def get_stress(self, atoms):
207 1 tkerber
        self.update(atoms)
208 1 tkerber
        return self.stress.copy()
209 1 tkerber
210 1 tkerber
    def calculate(self, atoms):
211 1 tkerber
        self.positions = atoms.get_positions().copy()
212 1 tkerber
        self.cell = atoms.get_cell().copy()
213 1 tkerber
        self.pbc = atoms.get_pbc().copy()
214 1 tkerber
215 1 tkerber
        self.write_files()
216 1 tkerber
217 1 tkerber
        self.write_inp(atoms)
218 1 tkerber
219 1 tkerber
        abinit = os.environ['ABINIT_SCRIPT']
220 1 tkerber
        locals = {'label': self.label}
221 1 tkerber
222 1 tkerber
        # Now, because (stupidly) abinit when it finds a name it uses nameA
223 1 tkerber
        # and when nameA exists it uses nameB, etc.
224 1 tkerber
        # we need to rename our *.txt file to *.txt.bak
225 1 tkerber
        filename = self.label + '.txt'
226 1 tkerber
        if islink(filename) or isfile(filename):
227 1 tkerber
            os.rename(filename, filename+'.bak')
228 1 tkerber
229 1 tkerber
        execfile(abinit, {}, locals)
230 1 tkerber
        exitcode = locals['exitcode']
231 1 tkerber
        if exitcode != 0:
232 1 tkerber
            raise RuntimeError(('Abinit exited with exit code: %d.  ' +
233 1 tkerber
                                'Check %s.log for more information.') %
234 1 tkerber
                               (exitcode, self.label))
235 1 tkerber
236 1 tkerber
        self.read()
237 1 tkerber
238 1 tkerber
        self.converged = True
239 1 tkerber
240 1 tkerber
    def write_files(self):
241 1 tkerber
        """Write input parameters to files-file."""
242 1 tkerber
        fh = open(self.label + '.files', 'w')
243 1 tkerber
244 1 tkerber
        import getpass
245 1 tkerber
        #find a suitable default scratchdir (should be writeable!)
246 1 tkerber
        username=getpass.getuser()
247 1 tkerber
248 1 tkerber
        if os.access("/scratch/"+username,os.W_OK):
249 1 tkerber
                scratch = "/scratch/"+username
250 1 tkerber
        elif os.access("/scratch/",os.W_OK):
251 1 tkerber
                scratch = "/scratch/"
252 1 tkerber
        else:
253 1 tkerber
                if os.access(os.curdir,os.W_OK):
254 1 tkerber
                        scratch = os.curdir #if no /scratch use curdir
255 1 tkerber
                else:
256 1 tkerber
                        raise IOError,"No suitable scratch directory and no write access to current dir"
257 1 tkerber
258 1 tkerber
        fh.write('%s\n' % (self.label+'.in')) # input
259 1 tkerber
        fh.write('%s\n' % (self.label+'.txt')) # output
260 1 tkerber
        fh.write('%s\n' % (self.label+'i')) # input
261 1 tkerber
        fh.write('%s\n' % (self.label+'o')) # output
262 1 tkerber
        # scratch files
263 1 tkerber
        fh.write('%s\n' % (os.path.join(scratch, self.label+'.abinit')))
264 1 tkerber
        # Provide the psp files
265 1 tkerber
        for ppp in self.ppp_list:
266 1 tkerber
            fh.write('%s\n' % (ppp)) # psp file path
267 1 tkerber
268 1 tkerber
        fh.close()
269 1 tkerber
270 1 tkerber
    def set_inp(self, key, value):
271 1 tkerber
        """Set INPUT parameter."""
272 1 tkerber
        self.inp[key] = value
273 1 tkerber
274 1 tkerber
    def write_inp(self, atoms):
275 1 tkerber
        """Write input parameters to in-file."""
276 1 tkerber
        fh = open(self.label + '.in', 'w')
277 1 tkerber
278 1 tkerber
        inp = {
279 1 tkerber
            #'SystemLabel': self.label,
280 1 tkerber
            #'LatticeConstant': 1.0,
281 1 tkerber
            'natom': len(atoms),
282 1 tkerber
            'charge': self.charge,
283 1 tkerber
            'nband': self.nbands,
284 1 tkerber
            #'DM.UseSaveDM': self.converged,
285 1 tkerber
            #'SolutionMethod': 'diagon',
286 1 tkerber
            'npulayit': self.pulay, # default 7
287 1 tkerber
            'diemix': self.mix
288 1 tkerber
            }
289 1 tkerber
290 1 tkerber
        if self.ecut is not None:
291 1 tkerber
            inp['ecut'] = str(self.ecut)+' eV' # default Ha
292 1 tkerber
293 1 tkerber
        if self.width is not None:
294 1 tkerber
            inp['tsmear'] = str(self.width)+' eV' # default Ha
295 1 tkerber
            fh.write('occopt 3 # Fermi-Dirac smearing\n')
296 1 tkerber
297 1 tkerber
        inp['ixc'] = { # default 1
298 1 tkerber
            'LDA':     7,
299 1 tkerber
            'PBE':    11,
300 1 tkerber
            'revPBE': 14,
301 1 tkerber
            'RPBE':   15,
302 1 tkerber
            'WC':     23
303 1 tkerber
            }[self.xc]
304 1 tkerber
305 1 tkerber
        magmoms = atoms.get_initial_magnetic_moments()
306 1 tkerber
        if magmoms.any():
307 1 tkerber
            inp['nsppol'] = 2
308 1 tkerber
            fh.write('spinat\n')
309 1 tkerber
            for n, M in enumerate(magmoms):
310 1 tkerber
                if M != 0:
311 1 tkerber
                    fh.write('%.14f %.14f %.14f\n' % (0, 0, M))
312 1 tkerber
        else:
313 1 tkerber
            inp['nsppol'] = 1
314 1 tkerber
            #fh.write('spinat\n')
315 1 tkerber
            #for n, M in enumerate(magmoms):
316 1 tkerber
            #    if M != 0:
317 1 tkerber
            #        fh.write('%.14f\n' % (M))
318 1 tkerber
319 1 tkerber
        inp.update(self.inp)
320 1 tkerber
321 1 tkerber
        for key, value in inp.items():
322 1 tkerber
            if value is None:
323 1 tkerber
                continue
324 1 tkerber
325 1 tkerber
            if isinstance(value, list):
326 1 tkerber
                fh.write('%block %s\n' % key)
327 1 tkerber
                for line in value:
328 1 tkerber
                    fh.write(' '.join(['%s' % x for x in line]) + '\n')
329 1 tkerber
                fh.write('%endblock %s\n' % key)
330 1 tkerber
331 1 tkerber
            unit = keys_with_units.get(inpify(key))
332 1 tkerber
            if unit is None:
333 1 tkerber
                fh.write('%s %s\n' % (key, value))
334 1 tkerber
            else:
335 1 tkerber
                if 'fs**2' in unit:
336 1 tkerber
                    value /= fs**2
337 1 tkerber
                elif 'fs' in unit:
338 1 tkerber
                    value /= fs
339 1 tkerber
                fh.write('%s %f %s\n' % (key, value, unit))
340 1 tkerber
341 1 tkerber
        fh.write('#Definition of the unit cell\n')
342 1 tkerber
        fh.write('acell\n')
343 1 tkerber
        fh.write('%.14f %.14f %.14f Angstrom\n' %  (1.0, 1.0, 1.0))
344 1 tkerber
        fh.write('rprim\n')
345 1 tkerber
        for v in self.cell:
346 1 tkerber
            fh.write('%.14f %.14f %.14f\n' %  tuple(v))
347 1 tkerber
348 1 tkerber
        fh.write('chkprim 0 # Allow non-primitive cells\n')
349 1 tkerber
350 1 tkerber
        fh.write('#Definition of the atom types\n')
351 1 tkerber
        fh.write('ntypat %d\n' % (len(self.species)))
352 1 tkerber
        fh.write('znucl')
353 1 tkerber
        for n, Z in enumerate(self.species):
354 1 tkerber
            fh.write(' %d' % (Z))
355 1 tkerber
        fh.write('\n')
356 1 tkerber
        fh.write('#Enumerate different atomic species\n')
357 1 tkerber
        fh.write('typat')
358 1 tkerber
        fh.write('\n')
359 1 tkerber
        self.types = []
360 1 tkerber
        for Z in self.numbers:
361 1 tkerber
            for n, Zs in enumerate(self.species):
362 1 tkerber
                if Z == Zs:
363 1 tkerber
                    self.types.append(n+1)
364 1 tkerber
        for n, type in enumerate(self.types):
365 1 tkerber
            fh.write(' %d' % (type))
366 1 tkerber
            if n > 1 and ((n % self.n_entries_int) == 1):
367 1 tkerber
                fh.write('\n')
368 1 tkerber
        fh.write('\n')
369 1 tkerber
370 1 tkerber
        fh.write('#Definition of the atoms\n')
371 1 tkerber
        fh.write('xangst\n')
372 1 tkerber
        a = 0
373 1 tkerber
        for pos, Z in zip(self.positions, self.numbers):
374 1 tkerber
            a += 1
375 1 tkerber
            fh.write('%.14f %.14f %.14f\n' %  tuple(pos))
376 1 tkerber
377 1 tkerber
        if self.kpts is not None:
378 1 tkerber
            fh.write('kptopt %d\n' % (1))
379 1 tkerber
            fh.write('ngkpt ')
380 1 tkerber
            fh.write('%d %d %d\n' %  tuple(self.kpts))
381 1 tkerber
382 1 tkerber
        fh.write('#Definition of the SCF procedure\n')
383 1 tkerber
        fh.write('toldfe %.1g\n' %  self.toldfe)
384 1 tkerber
        fh.write('chkexit 1 # abinit.exit file in the running directory terminates after the current SCF\n')
385 1 tkerber
386 1 tkerber
        fh.close()
387 1 tkerber
388 1 tkerber
    def read_fermi(self):
389 1 tkerber
        """Method that reads Fermi energy in Hartree from the output file
390 1 tkerber
        and returns it in eV"""
391 1 tkerber
        E_f=None
392 1 tkerber
        filename = self.label + '.txt'
393 1 tkerber
        text = open(filename).read().lower()
394 1 tkerber
        assert 'error' not in text
395 1 tkerber
        for line in iter(text.split('\n')):
396 1 tkerber
            if line.rfind('fermi (or homo) energy (hartree) =') > -1:
397 1 tkerber
                E_f = float(line.split('=')[1].strip().split()[0])
398 1 tkerber
        return E_f*Hartree
399 1 tkerber
400 1 tkerber
    def read_kpts_info(self, kpt=0, spin=0, mode='eigenvalues'):
401 1 tkerber
        """ Returns list of eigenvalues, occupations, kpts weights, or
402 1 tkerber
        kpts coordinates for given kpt and spin"""
403 1 tkerber
        # output may look like this (or without occupation entries); 8 entries per line:
404 1 tkerber
        #
405 1 tkerber
        #  Eigenvalues (hartree) for nkpt=  20  k points:
406 1 tkerber
        # kpt#   1, nband=  3, wtk=  0.01563, kpt=  0.0625  0.0625  0.0625 (reduced coord)
407 1 tkerber
        #  -0.09911   0.15393   0.15393
408 1 tkerber
        #      occupation numbers for kpt#   1
409 1 tkerber
        #   2.00000   0.00000   0.00000
410 1 tkerber
        # kpt#   2, nband=  3, wtk=  0.04688, kpt=  0.1875  0.0625  0.0625 (reduced coord)
411 1 tkerber
        # ...
412 1 tkerber
        #
413 1 tkerber
        assert mode in ['eigenvalues' , 'occupations', 'ibz_k_points', 'k_point_weights'], 'mode not in [\'eigenvalues\' , \'occupations\', \'ibz_k_points\', \'k_point_weights\']'
414 1 tkerber
        # number of lines of eigenvalues/occupations for a kpt
415 1 tkerber
        n_entry_lines = max(1, int(self.nbands/self.n_entries_float))
416 1 tkerber
        #
417 1 tkerber
        filename = self.label + '.txt'
418 1 tkerber
        text = open(filename).read().lower()
419 1 tkerber
        assert 'error' not in text
420 1 tkerber
        lines = iter(text.split('\n'))
421 1 tkerber
        text_list = []
422 1 tkerber
        # find the begining line of eigenvalues
423 1 tkerber
        contains_eigenvalues = False
424 1 tkerber
        for line in lines:
425 1 tkerber
            #if line.rfind('eigenvalues (hartree) for nkpt') > -1: #MDTMP
426 1 tkerber
            if line.rfind('eigenvalues (   ev  ) for nkpt') > -1:
427 1 tkerber
                n_kpts = int(line.split('nkpt=')[1].strip().split()[0])
428 1 tkerber
                contains_eigenvalues = True
429 1 tkerber
                break
430 1 tkerber
        # find the end line of eigenvalues starting from linenum
431 1 tkerber
        for line in lines:
432 1 tkerber
            text_list.append(line)
433 1 tkerber
            if not line.strip(): # find a blank line
434 1 tkerber
                break
435 1 tkerber
        # remove last (blank) line
436 1 tkerber
        text_list = text_list[:-1]
437 1 tkerber
438 1 tkerber
        assert contains_eigenvalues, 'No eigenvalues found in the output'
439 1 tkerber
440 1 tkerber
        # join text eigenvalues description with eigenvalues
441 1 tkerber
        # or occupation numbers for kpt# with occupations
442 1 tkerber
        contains_occupations = False
443 1 tkerber
        for line in text_list:
444 1 tkerber
            if line.rfind('occupation numbers') > -1:
445 1 tkerber
                contains_occupations = True
446 1 tkerber
                break
447 1 tkerber
        if mode == 'occupations':
448 1 tkerber
            assert contains_occupations, 'No occupations found in the output'
449 1 tkerber
450 1 tkerber
        if contains_occupations:
451 1 tkerber
            range_kpts = 2*n_kpts
452 1 tkerber
        else:
453 1 tkerber
            range_kpts = n_kpts
454 1 tkerber
        #
455 1 tkerber
        values_list = []
456 1 tkerber
        offset = 0
457 1 tkerber
        for kpt_entry in range(range_kpts):
458 1 tkerber
            full_line = ''
459 1 tkerber
            for entry_line in range(n_entry_lines+1):
460 1 tkerber
                full_line = full_line+str(text_list[offset+entry_line])
461 1 tkerber
            first_line = text_list[offset]
462 1 tkerber
            if mode == 'occupations':
463 1 tkerber
                if first_line.rfind('occupation numbers') > -1:
464 1 tkerber
                    # extract numbers
465 1 tkerber
                    full_line = [float(v) for v in full_line.split('#')[1].strip().split()[1:]]
466 1 tkerber
                    values_list.append(full_line)
467 1 tkerber
            elif mode in ['eigenvalues', 'ibz_k_points', 'k_point_weights']:
468 1 tkerber
                if first_line.rfind('reduced coord') > -1:
469 1 tkerber
                    # extract numbers
470 1 tkerber
                    if mode == 'eigenvalues':
471 1 tkerber
                        #full_line = [Hartree*float(v) for v in full_line.split(')')[1].strip().split()[:]] # MDTMP
472 1 tkerber
                        full_line = [float(v) for v in full_line.split(')')[1].strip().split()[:]]
473 1 tkerber
                    elif mode == 'ibz_k_points':
474 1 tkerber
                        full_line = [float(v) for v in full_line.split('kpt=')[1].strip().split('(')[0].split()]
475 1 tkerber
                    else:
476 1 tkerber
                        full_line = float(full_line.split('wtk=')[1].strip().split(',')[0].split()[0])
477 1 tkerber
                    values_list.append(full_line)
478 1 tkerber
            offset = offset+n_entry_lines+1
479 1 tkerber
        #
480 1 tkerber
        if mode in ['occupations', 'eigenvalues']:
481 1 tkerber
            return np.array(values_list[kpt])
482 1 tkerber
        else:
483 1 tkerber
            return np.array(values_list)
484 1 tkerber
485 1 tkerber
    def read(self):
486 1 tkerber
        """Read results from ABINIT's text-output file."""
487 1 tkerber
        filename = self.label + '.txt'
488 1 tkerber
        text = open(filename).read().lower()
489 1 tkerber
        assert 'error' not in text
490 1 tkerber
        assert 'was not enough scf cycles to converge' not in text
491 1 tkerber
        # some consistency ckecks
492 1 tkerber
        for line in iter(text.split('\n')):
493 1 tkerber
            if line.rfind('natom  ') > -1:
494 1 tkerber
                natom = int(line.split()[-1])
495 1 tkerber
                assert natom == len(self.numbers)
496 1 tkerber
        for line in iter(text.split('\n')):
497 1 tkerber
            if line.rfind('znucl  ') > -1:
498 1 tkerber
                znucl = [float(Z) for Z in line.split()[1:]]
499 1 tkerber
                for n, Z in enumerate(self.species):
500 1 tkerber
                    assert Z == znucl[n]
501 1 tkerber
        lines = text.split('\n')
502 1 tkerber
        for n, line in enumerate(lines):
503 1 tkerber
            if line.rfind(' typat  ') > -1:
504 1 tkerber
                nlines = len(self.numbers) / self.n_entries_int
505 1 tkerber
                typat = [int(t) for t in line.split()[1:]] # first line
506 1 tkerber
                for nline in range(nlines): # remaining lines
507 1 tkerber
                    for t in lines[1 + n + nline].split()[:]:
508 1 tkerber
                        typat.append(int(t))
509 1 tkerber
        for n, t in enumerate(self.types):
510 1 tkerber
            assert t == typat[n]
511 1 tkerber
512 1 tkerber
        lines = iter(text.split('\n'))
513 1 tkerber
        # Stress:
514 1 tkerber
        # Printed in the output in the following format [Hartree/Bohr^3]:
515 1 tkerber
        # sigma(1 1)=  4.02063464E-04  sigma(3 2)=  0.00000000E+00
516 1 tkerber
        # sigma(2 2)=  4.02063464E-04  sigma(3 1)=  0.00000000E+00
517 1 tkerber
        # sigma(3 3)=  4.02063464E-04  sigma(2 1)=  0.00000000E+00
518 1 tkerber
        for line in lines:
519 1 tkerber
            if line.rfind('cartesian components of stress tensor (hartree/bohr^3)') > -1:
520 1 tkerber
                self.stress = np.empty((3, 3))
521 1 tkerber
                for i in range(3):
522 1 tkerber
                    entries = lines.next().split()
523 1 tkerber
                    self.stress[i,i] = float(entries[2])
524 1 tkerber
                    self.stress[min(3, 4-i)-1, max(1, 2-i)-1] = float(entries[5])
525 1 tkerber
                    self.stress[max(1, 2-i)-1, min(3, 4-i)-1] = float(entries[5])
526 1 tkerber
                self.stress = self.stress*Hartree/Bohr**3
527 1 tkerber
                break
528 1 tkerber
        else:
529 1 tkerber
            raise RuntimeError
530 1 tkerber
531 1 tkerber
        # Energy [Hartree]:
532 1 tkerber
        # Warning: Etotal could mean both electronic energy and free energy!
533 1 tkerber
        for line in iter(text.split('\n')):
534 1 tkerber
            if line.rfind('>>>>> internal e=') > -1:
535 1 tkerber
                self.etotal = float(line.split('=')[-1])*Hartree
536 1 tkerber
                for line1 in iter(text.split('\n')):
537 1 tkerber
                    if line1.rfind('>>>>>>>>> etotal=') > -1:
538 1 tkerber
                        self.efree = float(line1.split('=')[-1])*Hartree
539 1 tkerber
                        break
540 1 tkerber
                else:
541 1 tkerber
                    raise RuntimeError
542 1 tkerber
                break
543 1 tkerber
        else:
544 1 tkerber
            for line2 in iter(text.split('\n')):
545 1 tkerber
                if line2.rfind('>>>>>>>>> etotal=') > -1:
546 1 tkerber
                    self.etotal = float(line2.split('=')[-1])*Hartree
547 1 tkerber
                    self.efree = self.etotal
548 1 tkerber
                    break
549 1 tkerber
            else:
550 1 tkerber
                raise RuntimeError
551 1 tkerber
552 1 tkerber
        # Forces:
553 1 tkerber
        for line in lines:
554 1 tkerber
            if line.rfind('cartesian forces (ev/angstrom) at end:') > -1:
555 1 tkerber
                forces = []
556 1 tkerber
                for i in range(len(self.numbers)):
557 1 tkerber
                    forces.append(np.array([float(f) for f in lines.next().split()[1:]]))
558 1 tkerber
                self.forces = np.array(forces)
559 1 tkerber
                break
560 1 tkerber
        else:
561 1 tkerber
            raise RuntimeError
562 1 tkerber
563 1 tkerber
def inpify(key):
564 1 tkerber
    return key.lower().replace('_', '').replace('.', '').replace('-', '')
565 1 tkerber
566 1 tkerber
567 1 tkerber
keys_with_units = {
568 1 tkerber
    }
569 1 tkerber
#keys_with_units = {
570 1 tkerber
#    'paoenergyshift': 'eV',
571 1 tkerber
#    'zmunitslength': 'Bohr',
572 1 tkerber
#    'zmunitsangle': 'rad',
573 1 tkerber
#    'zmforcetollength': 'eV/Ang',
574 1 tkerber
#    'zmforcetolangle': 'eV/rad',
575 1 tkerber
#    'zmmaxdispllength': 'Ang',
576 1 tkerber
#    'zmmaxdisplangle': 'rad',
577 1 tkerber
#    'ecut': 'eV',
578 1 tkerber
#    'dmenergytolerance': 'eV',
579 1 tkerber
#    'electronictemperature': 'eV',
580 1 tkerber
#    'oneta': 'eV',
581 1 tkerber
#    'onetaalpha': 'eV',
582 1 tkerber
#    'onetabeta': 'eV',
583 1 tkerber
#    'onrclwf': 'Ang',
584 1 tkerber
#    'onchemicalpotentialrc': 'Ang',
585 1 tkerber
#    'onchemicalpotentialtemperature': 'eV',
586 1 tkerber
#    'mdmaxcgdispl': 'Ang',
587 1 tkerber
#    'mdmaxforcetol': 'eV/Ang',
588 1 tkerber
#    'mdmaxstresstol': 'eV/Ang**3',
589 1 tkerber
#    'mdlengthtimestep': 'fs',
590 1 tkerber
#    'mdinitialtemperature': 'eV',
591 1 tkerber
#    'mdtargettemperature': 'eV',
592 1 tkerber
#    'mdtargetpressure': 'eV/Ang**3',
593 1 tkerber
#    'mdnosemass': 'eV*fs**2',
594 1 tkerber
#    'mdparrinellorahmanmass': 'eV*fs**2',
595 1 tkerber
#    'mdtaurelax': 'fs',
596 1 tkerber
#    'mdbulkmodulus': 'eV/Ang**3',
597 1 tkerber
#    'mdfcdispl': 'Ang',
598 1 tkerber
#    'warningminimumatomicdistance': 'Ang',
599 1 tkerber
#    'rcspatial': 'Ang',
600 1 tkerber
#    'kgridcutoff': 'Ang',
601 1 tkerber
#    'latticeconstant': 'Ang'}