Coverage for /builds/ase/ase/ase/calculators/genericfileio.py : 88.89%

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
1from os import PathLike
2from pathlib import Path
3from typing import Iterable, Mapping, Any
4from abc import ABC, abstractmethod
6from ase.calculators.abc import GetOutputsMixin
7from ase.calculators.calculator import BaseCalculator
10def read_stdout(args, createfile=None):
11 """Run command in tempdir and return standard output.
13 Helper function for getting version numbers of DFT codes.
14 Most DFT codes don't implement a --version flag, so in order to
15 determine the code version, we just run the code until it prints
16 a version number."""
17 import tempfile
18 from subprocess import Popen, PIPE
19 with tempfile.TemporaryDirectory() as directory:
20 if createfile is not None:
21 path = Path(directory) / createfile
22 path.touch()
23 proc = Popen(args,
24 stdout=PIPE,
25 stderr=PIPE,
26 stdin=PIPE,
27 cwd=directory,
28 encoding='ascii')
29 stdout, _ = proc.communicate()
30 # Exit code will be != 0 because there isn't an input file
31 return stdout
34class CalculatorTemplate(ABC):
35 def __init__(self, name: str, implemented_properties: Iterable[str]):
36 self.name = name
37 self.implemented_properties = frozenset(implemented_properties)
39 @abstractmethod
40 def write_input(self, directory, atoms, parameters, properties):
41 ...
43 @abstractmethod
44 def execute(self, directory, profile):
45 ...
47 @abstractmethod
48 def read_results(self, directory: PathLike) -> Mapping[str, Any]:
49 ...
52class GenericFileIOCalculator(BaseCalculator, GetOutputsMixin):
53 def __init__(self, *, template, profile, directory, parameters=None):
54 self.template = template
55 self.profile = profile
57 # Maybe we should allow directory to be a factory, so
58 # calculators e.g. produce new directories on demand.
59 self.directory = Path(directory)
61 super().__init__(parameters)
63 def set(self, *args, **kwargs):
64 raise RuntimeError('No setting parameters for now, please. '
65 'Just create new calculators.')
67 def __repr__(self):
68 return '{}({})'.format(type(self).__name__, self.template.name)
70 @property
71 def implemented_properties(self):
72 return self.template.implemented_properties
74 @property
75 def name(self):
76 return self.template.name
78 def write_inputfiles(self, atoms, properties):
79 # SocketIOCalculators like to write inputfiles
80 # without calculating.
81 self.directory.mkdir(exist_ok=True, parents=True)
82 self.template.write_input(
83 atoms=atoms,
84 parameters=self.parameters,
85 properties=properties,
86 directory=self.directory)
88 def calculate(self, atoms, properties, system_changes):
89 self.write_inputfiles(atoms, properties)
90 self.template.execute(self.directory, self.profile)
91 self.results = self.template.read_results(self.directory)
92 # XXX Return something useful?
94 def _outputmixin_get_results(self):
95 return self.results