Coverage for /builds/hweiske/ase/ase/calculators/onetep.py: 37.78%
45 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-22 11:22 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-22 11:22 +0000
1"""ONETEP interface for the Atomic Simulation Environment (ASE) package
3T. Demeyere, T.Demeyere@soton.ac.uk (2023)
5https://onetep.org"""
7from os import environ
9from ase.calculators.genericfileio import (BaseProfile, CalculatorTemplate,
10 GenericFileIOCalculator,
11 read_stdout)
12from ase.io import read, write
15class OnetepProfile(BaseProfile):
16 """
17 ONETEP profile class, additional "old" parameter
18 is automatically passed for now if the user uses the
19 now deprecated "ASE_ONETEP_COMMAND".
20 """
22 def __init__(self, binary, old=False, **kwargs):
23 """
24 Parameters
25 ----------
26 binary: str
27 Path to the ONETEP binary.
28 old: bool
29 If True, will use the old ASE_ONETEP_COMMAND
30 interface.
31 **kwargs: dict
32 Additional kwargs are passed to the BaseProfile
33 class.
34 """
35 super().__init__(**kwargs)
36 self.binary = binary
37 self.old = old
39 def version(self):
40 lines = read_stdout(self.binary)
41 return self.parse_version(lines)
43 def parse_version(lines):
44 return '1.0.0'
46 def get_calculator_command(self, inputfile):
47 if self.old:
48 return self.binary.split() + [str(inputfile)]
49 else:
50 return [self.binary, str(inputfile)]
53class OnetepTemplate(CalculatorTemplate):
54 _label = 'onetep'
56 def __init__(self, append):
57 super().__init__(
58 'ONETEP',
59 implemented_properties=[
60 'energy',
61 'free_energy',
62 'forces',
63 'stress'])
64 self.inputname = f'{self._label}.dat'
65 self.outputname = f'{self._label}.out'
66 self.errorname = f'{self._label}.err'
67 self.append = append
69 def execute(self, directory, profile):
70 profile.run(directory, self.inputname, self.outputname,
71 self.errorname, append=self.append)
73 def read_results(self, directory):
74 output_path = directory / self.outputname
75 atoms = read(output_path, format='onetep-out')
76 return dict(atoms.calc.properties())
78 def write_input(self, profile, directory, atoms, parameters, properties):
79 input_path = directory / self.inputname
80 write(input_path, atoms, format='onetep-in',
81 properties=properties, **parameters)
83 def load_profile(self, cfg, **kwargs):
84 return OnetepProfile.from_config(cfg, self.name, **kwargs)
87class Onetep(GenericFileIOCalculator):
88 """
89 Class for the ONETEP calculator, uses ase/io/onetep.py.
90 Need the env variable "ASE_ONETEP_COMMAND" defined to
91 properly work. All other options are passed in kwargs.
93 Parameters
94 ----------
95 autorestart : Bool
96 When activated, manages restart keywords automatically.
97 append: Bool
98 Append to output instead of overwriting.
99 directory: str
100 Directory where to run the calculation(s).
101 keywords: dict
102 Dictionary with ONETEP keywords to write,
103 keywords with lists as values will be
104 treated like blocks, with each element
105 of list being a different line.
106 xc: str
107 DFT xc to use e.g (PBE, RPBE, ...).
108 ngwfs_count: int|list|dict
109 Behaviour depends on the type:
110 int: every species will have this amount
111 of ngwfs.
112 list: list of int, will be attributed
113 alphabetically to species:
114 dict: keys are species name(s),
115 value are their number:
116 ngwfs_radius: int|list|dict
117 Behaviour depends on the type:
118 float: every species will have this radius.
119 list: list of float, will be attributed
120 alphabetically to species:
121 [10.0, 9.0]
122 dict: keys are species name(s),
123 value are their radius:
124 {'Na': 9.0, 'Cl': 10.0}
125 pseudopotentials: list|dict
126 Behaviour depends on the type:
127 list: list of string(s), will be attributed
128 alphabetically to specie(s):
129 ['Cl.usp', 'Na.usp']
130 dict: keys are species name(s) their
131 value are the pseudopotential file to use:
132 {'Na': 'Na.usp', 'Cl': 'Cl.usp'}
133 pseudo_path: str
134 Where to look for pseudopotential, correspond
135 to the pseudo_path keyword of ONETEP.
137 .. note::
138 write_forces is always turned on by default
139 when using this interface.
141 .. note::
142 Little to no check is performed on the keywords provided by the user
143 via the keyword dictionary, it is the user responsibility that they
144 are valid ONETEP keywords.
145 """
147 def __init__(
148 self,
149 *,
150 profile=None,
151 directory='.',
152 parallel_info=None,
153 parallel=True,
154 **kwargs):
156 self.keywords = kwargs.get('keywords', None)
157 self.template = OnetepTemplate(
158 append=kwargs.pop('append', False)
159 )
161 if 'ASE_ONETEP_COMMAND' in environ and profile is None:
162 import warnings
163 warnings.warn("using ASE_ONETEP_COMMAND env is \
164 deprecated, please use OnetepProfile",
165 FutureWarning)
166 profile = OnetepProfile(environ['ASE_ONETEP_COMMAND'], old=True)
168 super().__init__(profile=profile, template=self.template,
169 directory=directory,
170 parameters=kwargs,
171 parallel=parallel,
172 parallel_info=parallel_info)