Coverage for /builds/ase/ase/ase/calculators/octopus.py : 74.55%

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"""ASE-interface to Octopus.
3Ask Hjorth Larsen <asklarsen@gmail.com>
4Carlos de Armas
6http://tddft.org/programs/octopus/
7"""
9import numpy as np
10from ase.io.octopus.input import process_special_kwargs, generate_input
11from ase.io.octopus.output import read_eigenvalues_file, read_static_info
12from ase.calculators.genericfileio import (CalculatorTemplate,
13 GenericFileIOCalculator)
16class OctopusIOError(IOError):
17 pass
20class OctopusProfile:
21 def __init__(self, argv):
22 self.argv = argv
24 def version(self):
25 from subprocess import check_output
26 import re
27 txt = check_output(self.argv + ['--version']).decode('ascii')
28 match = re.match(r'octopus\s*(.+)', txt)
29 # With MPI it prints the line for each rank, but we just match
30 # the first line.
31 return match.group(1)
33 def run(self, directory, outputfile):
34 from subprocess import check_call
35 with open(directory / outputfile, 'w') as fd:
36 check_call(self.argv, stdout=fd, cwd=directory)
39class OctopusTemplate(CalculatorTemplate):
40 def __init__(self):
41 super().__init__(
42 name='octopus',
43 implemented_properties=['energy', 'forces', 'dipole', 'stress'],
44 )
46 def read_results(self, directory):
47 """Read octopus output files and extract data."""
48 results = {}
49 with open(directory / 'static/info') as fd:
50 results.update(read_static_info(fd))
52 # If the eigenvalues file exists, we get the eigs/occs from that one.
53 # This probably means someone ran Octopus in 'unocc' mode to
54 # get eigenvalues (e.g. for band structures), and the values in
55 # static/info will be the old (selfconsistent) ones.
56 eigpath = directory / 'static/eigenvalues'
57 if eigpath.is_file():
58 with open(eigpath) as fd:
59 kpts, eigs, occs = read_eigenvalues_file(fd)
60 kpt_weights = np.ones(len(kpts)) # XXX ? Or 1 / len(kpts) ?
61 # XXX New Octopus probably has symmetry reduction !!
62 results.update(eigenvalues=eigs, occupations=occs,
63 ibz_k_points=kpts,
64 k_point_weights=kpt_weights)
65 return results
67 def execute(self, directory, profile):
68 profile.run(directory, 'octopus.out')
70 def write_input(self, directory, atoms, parameters, properties):
71 txt = generate_input(atoms, process_special_kwargs(atoms, parameters))
72 inp = directory / 'inp'
73 inp.write_text(txt)
76class Octopus(GenericFileIOCalculator):
77 """Octopus calculator.
79 The label is always assumed to be a directory."""
81 def __init__(self,
82 profile=None,
83 directory='.',
84 **kwargs):
85 """Create Octopus calculator.
87 Label is always taken as a subdirectory.
88 Restart is taken to be a label."""
90 if profile is None:
91 profile = OctopusProfile(['octopus'])
93 super().__init__(profile=profile, template=OctopusTemplate(),
94 directory=directory,
95 parameters=kwargs)
97 @classmethod
98 def recipe(cls, **kwargs):
99 from ase import Atoms
100 system = Atoms()
101 calc = Octopus(CalculationMode='recipe', **kwargs)
102 system.calc = calc
103 try:
104 system.get_potential_energy()
105 except OctopusIOError:
106 pass
107 else:
108 raise OctopusIOError('Expected recipe, but found '
109 'useful physical output!')