Coverage for /builds/ase/ase/ase/calculators/acemolecule.py : 24.24%

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# type: ignore
2import os
3from copy import deepcopy
4from ase.io import read
5from ase.calculators.calculator import ReadError
6from ase.calculators.calculator import FileIOCalculator
9class ACE(FileIOCalculator):
10 '''
11 ACE-Molecule logfile reader
12 It has default parameters of each input section
13 And parameters' type = list of dictionaries
14 '''
15 name = 'ace'
16 implemented_properties = ['energy', 'forces', 'excitation-energy']
17 basic_list = [{
18 'Type': 'Scaling', 'Scaling': '0.35', 'Basis': 'Sinc',
19 'Grid': 'Sphere',
20 'KineticMatrix': 'Finite_Difference', 'DerivativesOrder': '7',
21 'GeometryFilename': None, 'NumElectrons': None}
22 ]
23 scf_list = [{
24 'ExchangeCorrelation': {'XFunctional': 'GGA_X_PBE',
25 'CFunctional': 'GGA_C_PBE'},
26 'NumberOfEigenvalues': None,
27 }]
29 force_list = [{'ForceDerivative': 'Potential'}]
30 tddft_list = [{
31 'SortOrbital': 'Order', 'MaximumOrder': '10',
32 'ExchangeCorrelation': {'XFunctional': 'GGA_X_PBE',
33 'CFunctional': 'GGA_C_PBE'},
34 }]
36 order_list = ['BasicInformation', 'Guess', 'Scf']
37 guess_list = [{}]
38 default_parameters = {'BasicInformation': basic_list, 'Guess': guess_list,
39 'Scf': scf_list, 'Force': force_list,
40 'TDDFT': tddft_list, 'order': order_list}
42 def __init__(
43 self, restart=None,
44 ignore_bad_restart_file=FileIOCalculator._deprecated,
45 label='ace', atoms=None, command=None,
46 basisfile=None, **kwargs):
47 FileIOCalculator.__init__(self, restart, ignore_bad_restart_file,
48 label, atoms, command=command, **kwargs)
50 def set(self, **kwargs):
51 '''Update parameters self.parameter member variable.
52 1. Add default values for repeated parameter sections with
53 self.default_parameters using order.
54 2. Also add empty dictionary as an indicator for section existence
55 if no relevant default_parameters exist.
56 3. Update parameters from arguments.
58 Returns
59 =======
60 Updated parameter
61 '''
62 new_parameters = deepcopy(self.parameters)
64 changed_parameters = FileIOCalculator.set(self, **kwargs)
66 # Add default values for repeated parameter sections with
67 # self.default_parameters using order. Also add empty
68 # dictionary as an indicator for section existence if no
69 # relevant default_parameters exist.
70 if 'order' in kwargs:
71 new_parameters['order'] = kwargs['order']
72 section_sets = set(kwargs['order'])
73 for section_name in section_sets:
74 repeat = kwargs['order'].count(section_name)
75 if section_name in self.default_parameters.keys():
76 for i in range(repeat - 1):
77 new_parameters[section_name] += deepcopy(
78 self.default_parameters[section_name])
79 else:
80 new_parameters[section_name] = []
81 for i in range(repeat):
82 new_parameters[section_name].append({})
84 # Update parameters
85 for section in new_parameters['order']:
86 if section in kwargs.keys():
87 if isinstance(kwargs[section], dict):
88 kwargs[section] = [kwargs[section]]
90 i = 0
91 for section_param in kwargs[section]:
92 new_parameters[section][i] = update_parameter(
93 new_parameters[section][i], section_param)
94 i += 1
95 self.parameters = new_parameters
96 return changed_parameters
98 def read(self, label):
99 FileIOCalculator.read(self, label)
100 filename = self.label + ".log"
102 with open(filename, 'r') as fd:
103 lines = fd.readlines()
104 if 'WARNING' in lines:
105 raise ReadError(
106 "Not convergy energy in log file {}.".format(filename))
107 if '! total energy' not in lines:
108 raise ReadError("Wrong ACE-Molecule log file {}.".format(filename))
110 if not os.path.isfile(filename):
111 raise ReadError(
112 "Wrong ACE-Molecule input file {}.".format(filename))
114 self.read_results()
116 def write_input(self, atoms, properties=None, system_changes=None):
117 '''Initializes input parameters and xyz files. If force calculation is
118 requested, add Force section to parameters if not exists.
120 Parameters
121 ==========
122 atoms: ASE atoms object.
123 properties: List of properties to be calculated. Should be element
124 of self.implemented_properties.
125 system_chages: Ignored.
127 '''
128 FileIOCalculator.write_input(self, atoms, properties, system_changes)
129 with open(self.label + '.inp', 'w') as inputfile:
130 xyz_name = "{}.xyz".format(self.label)
131 atoms.write(xyz_name)
133 run_parameters = self.prepare_input(xyz_name, properties)
134 self.write_acemolecule_input(inputfile, run_parameters)
136 def prepare_input(self, geometry_filename, properties):
137 '''Initialize parameters dictionary based on geometry filename and
138 calculated properties.
140 Parameters
141 ==========
142 geometry_filename: Geometry (XYZ format) file path.
143 properties: Properties to be calculated.
145 Returns
146 =======
147 Updated version of self.parameters; geometry file and
148 optionally Force section are updated.
150 '''
151 copied_parameters = deepcopy(self.parameters)
152 if (properties is not None and "forces" in properties
153 and 'Force' not in copied_parameters['order']):
154 copied_parameters['order'].append('Force')
155 copied_parameters["BasicInformation"][0]["GeometryFilename"] = \
156 "{}.xyz".format(self.label)
157 copied_parameters["BasicInformation"][0]["GeometryFormat"] = "xyz"
158 return copied_parameters
160 def read_results(self):
161 '''Read calculation results, speficied by 'quantities' variable, from
162 the log file.
164 quantities
165 =======
166 energy : obtaing single point energy(eV) from log file
167 forces : obtaing force of each atom form log file
168 excitation-energy : it able to calculate TDDFT.
169 Return value is None. Result is not used.
170 atoms : ASE atoms object
172 '''
173 filename = self.label + '.log'
174 self.results = read(filename, format='acemolecule-out')
176 def write_acemolecule_section(self, fpt, section, depth=0):
177 '''Write parameters in each section of input
179 Parameters
180 ==========
181 fpt: ACE-Moleucle input file object. Should be write mode.
182 section: Dictionary of a parameter section.
183 depth: Nested input depth.
184 '''
185 for section, section_param in section.items():
186 if isinstance(section_param, str) or isinstance(
187 section_param, int) or isinstance(section_param, float):
188 fpt.write(
189 ' ' *
190 depth +
191 str(section) +
192 " " +
193 str(section_param) +
194 "\n")
195 else:
196 if isinstance(section_param, dict):
197 fpt.write(' ' * depth + "%% " + str(section) + "\n")
198 self.write_acemolecule_section(
199 fpt, section_param, depth + 1)
200 fpt.write(' ' * depth + "%% End\n")
201 if isinstance(section_param, list):
202 for val in section_param:
203 fpt.write(
204 ' ' *
205 depth +
206 str(section) +
207 " " +
208 str(val) +
209 "\n")
211 def write_acemolecule_input(self, fpt, param, depth=0):
212 '''Write ACE-Molecule input
214 ACE-Molecule input examples (not minimal)
215 %% BasicInformation
216 Type Scaling
217 Scaling 0.4
218 Basis Sinc
219 Cell 10.0
220 Grid Sphere
221 GeometryFormat xyz
222 SpinMultiplicity 3.0
223 Polarize 1
224 Centered 0
225 %% Pseudopotential
226 Pseudopotential 1
227 UsingDoubleGrid 0
228 FilterType Sinc
229 Format upf
230 PSFilePath /PATH/TO/UPF
231 PSFileSuffix .pbe-theos.UPF
232 %% End
233 GeometryFilename xyz/C.xyz
234 %% End
235 %% Guess
236 InitialGuess 3
237 InitialFilenames 001.cube
238 InitialFilenames 002.cube
239 %% End
240 %% Scf
241 IterateMaxCycle 150
242 ConvergenceType Energy
243 ConvergenceTolerance 0.00001
244 EnergyDecomposition 1
245 ComputeInitialEnergy 1
246 %% Diagonalize
247 Tolerance 0.000001
248 %% End
249 %% ExchangeCorrelation
250 XFunctional GGA_X_PBE
251 CFunctional GGA_C_PBE
252 %% End
253 %% Mixing
254 MixingMethod 1
255 MixingType Density
256 MixingParameter 0.5
257 PulayMixingParameter 0.1
258 %% End
259 %% End
261 Parameters
262 ==========
263 fpt: File object, should be write mode.
264 param: Dictionary of parameters. Also should contain
265 special 'order' section_name for parameter section ordering.
266 depth: Nested input depth.
268 Notes
269 =====
270 - Order of parameter section
271 (denoted using %% -- %% BasicInformation, %% Guess, etc.)
272 is important, because it determines calculation order.
273 For example, if Guess section comes after Scf section,
274 calculation will not run because Scf will tries to run
275 without initial Hamiltonian.
276 - Order of each parameter section-section_name pair is
277 not important unless their keys are the same.
278 - Indentation unimportant and capital letters are important.
279 '''
280 prefix = " " * depth
282 for i in range(len(param['order'])):
283 fpt.write(prefix + "%% " + param['order'][i] + "\n")
284 section_list = param[param['order'][i]]
285 if len(section_list) > 0:
286 section = section_list.pop(0)
287 self.write_acemolecule_section(fpt, section, 1)
288 fpt.write("%% End\n")
289 return
292def update_parameter(oldpar, newpar):
293 '''Update each section of parameter (oldpar) using newpar keys and values.
294 If section of newpar exist in oldpar,
295 - Replace the section_name with newpar's section_name if
296 oldvar section_name type is not dict.
297 - Append the section_name with newpar's section_name
298 if oldvar section_name type is list.
299 - If oldpar section_name type is dict, it is subsection.
300 So call update_parameter again.
301 otherwise, add the parameter section and section_name from newpar.
303 Parameters
304 ==========
305 oldpar: dictionary of original parameters to be updated.
306 newpar: dictionary containing parameter section and values to update.
308 Return
309 ======
310 Updated parameter dictionary.
311 '''
312 for section, section_param in newpar.items():
313 if section in oldpar:
314 if isinstance(section_param, dict):
315 oldpar[section] = update_parameter(
316 oldpar[section], section_param)
317 else:
318 oldpar[section] = section_param
319 else:
320 oldpar[section] = section_param
321 return oldpar