Révision a234c0e8
b/modules/dos_input.py | ||
---|---|---|
5 | 5 |
check_expect_val: Checks whether an option lies within its expected values. |
6 | 6 |
read_input: Sets up the variables of DockOnSurf by reading from an input file. |
7 | 7 |
""" |
8 |
import os.path |
|
8 | 9 |
import logging |
10 |
from configparser import ConfigParser, NoSectionError, NoOptionError, \ |
|
11 |
MissingSectionHeaderError, DuplicateOptionError |
|
12 |
|
|
13 |
logger = logging.getLogger('DockOnSurf') |
|
14 |
|
|
15 |
dos_inp = ConfigParser(inline_comment_prefixes='#', |
|
16 |
empty_lines_in_values=False) |
|
17 |
|
|
18 |
new_answers = {'n': False, 'none': False, 'nay': False, |
|
19 |
'y': True, 'sí': True, 'aye': True, 'sure': True} |
|
20 |
for answer, val in new_answers.items(): |
|
21 |
dos_inp.BOOLEAN_STATES[answer] = val |
|
22 |
turn_false_answers = [answer for answer in dos_inp.BOOLEAN_STATES |
|
23 |
if dos_inp.BOOLEAN_STATES[answer] is False] |
|
24 |
|
|
25 |
no_sect_err = "Section '%s' not found on input file" |
|
26 |
no_opt_err = "Option '%s' not found on section '%s'" |
|
27 |
num_error = "'%s' value must be a %s" |
|
28 |
unexp_error = "An unexpected error occurred" |
|
29 |
|
|
30 |
|
|
31 |
def try_command(command, expct_error_types: list, *args, **kwargs): |
|
32 |
"""Try to run a command and record exceptions (expected and not) on a log. |
|
33 |
|
|
34 |
@param command: method or function, the command to be executed. |
|
35 |
@param expct_error_types: tuple of tuples, every inner tuple is supposed to |
|
36 |
contain an exception type (eg. ValueError, TypeError, etc.) to be caught and |
|
37 |
a message to print in the log and on the screen explaining the exception. |
|
38 |
Error types that are not allow to be called with a custom message as only |
|
39 |
error argument are not supported. |
|
40 |
The outer tuple encloses all couples of error types and their relative |
|
41 |
messages. |
|
42 |
*args and **kwargs: arguments and keyword-arguments of the command to be |
|
43 |
executed. |
|
44 |
When trying to run 'command' with its args and kwargs, if an exception |
|
45 |
present on the 'error_types' occurs, its relative error message is recorded |
|
46 |
on the log and a same type exception is raised with the custom message. |
|
47 |
""" |
|
48 |
|
|
49 |
err = False |
|
50 |
try: |
|
51 |
return_val = command(*args, **kwargs) |
|
52 |
except Exception as e: |
|
53 |
print('I am in exce') |
|
54 |
for expct_err in expct_error_types: |
|
55 |
if isinstance(e, expct_err[0]): |
|
56 |
logger.error(expct_err[1]) |
|
57 |
err = expct_err[0](expct_err[1]) |
|
58 |
break |
|
59 |
else: |
|
60 |
logger.exception(unexp_error) |
|
61 |
err = e |
|
62 |
else: |
|
63 |
print('Here I am') |
|
64 |
err = False |
|
65 |
return return_val |
|
66 |
finally: |
|
67 |
print(err) |
|
68 |
if isinstance(err, BaseException): |
|
69 |
raise err |
|
9 | 70 |
|
10 | 71 |
|
11 |
def str2lst(cmplx_str): # TODO: enable deeper level of nested lists \ |
|
12 |
# TODO: (eg. '3 ((6 7) 8) 4') |
|
72 |
def str2lst(cmplx_str): # TODO: enable deeper level of nested lists |
|
13 | 73 |
"""Converts a string of integers, and groups of them, to a list. |
14 | 74 |
|
15 | 75 |
Keyword arguments: |
... | ... | |
25 | 85 |
eg. '128,(135 138;141] 87 {45, 68}' -> [128, 87, [135, 138, 141], [45, 68]] |
26 | 86 |
""" |
27 | 87 |
|
28 |
logger = logging.getLogger('DockOnSurf') |
|
29 |
|
|
30 |
error_msg = "Function argument should be a sequence of integer numbers " \ |
|
31 |
"separated by ',' ';' or ' '." \ |
|
88 |
# Checks |
|
89 |
error_msg = "Function argument should be a str,sequence of integer " \ |
|
90 |
"numbers separated by ',' ';' or ' '." \ |
|
32 | 91 |
"\nThey can be grouped in parentheses-like enclosers: '()', " \ |
33 | 92 |
"'[]' or {}. Nested groups are not allowed. \n" \ |
34 | 93 |
"eg. 128,(135 138;141) 87 {45, 68}" |
35 |
try: |
|
36 |
cmplx_str = cmplx_str.replace(',', ' ').replace(';', ' ').replace( |
|
37 |
'[', '(').replace(']', ')').replace('{', '(').replace('}', ')') |
|
38 |
list(map(int, cmplx_str.replace(')', '').replace('(', '').split())) |
|
39 |
except AttributeError: |
|
40 |
logger.error(error_msg) |
|
41 |
raise AttributeError(error_msg) |
|
42 |
except ValueError: # TODO Improve error handling |
|
43 |
logger.error(error_msg) |
|
44 |
raise ValueError(error_msg) |
|
94 |
cmplx_str = try_command(cmplx_str.replace, [(AttributeError, error_msg)], |
|
95 |
',', ' ') |
|
96 |
|
|
97 |
cmplx_str = cmplx_str.replace(';', ' ').replace('[', '(').replace( |
|
98 |
']', ')').replace('{', '(').replace('}', ')') |
|
99 |
|
|
100 |
try_command(list, [(ValueError, error_msg)], map(int, cmplx_str.replace( |
|
101 |
')', '').replace('(', '').split())) |
|
102 |
|
|
45 | 103 |
deepness = 0 |
46 | 104 |
for el in cmplx_str.split(): |
47 | 105 |
if '(' in el: |
... | ... | |
85 | 143 |
@raise ValueError: if the value is not among the expected ones. |
86 | 144 |
@return True if the value is among the expected ones. |
87 | 145 |
""" |
88 |
|
|
89 |
logger = logging.getLogger('DockOnSurf') |
|
90 |
|
|
91 | 146 |
adeq_val_err = "'%s' is not an adequate value.\n" \ |
92 | 147 |
"Adequate values: %s" |
93 | 148 |
if not any([exp_val in value for exp_val in expect_vals]): |
... | ... | |
97 | 152 |
return True |
98 | 153 |
|
99 | 154 |
|
100 |
def read_input(in_file): |
|
101 |
"""Sets up the variables of DockOnSurf by reading from an input file. |
|
102 |
|
|
103 |
The Format of the input file should be of a .INI type like most config files |
|
104 |
able to be managed by the configparser standard library. |
|
105 |
Sections should be capitalized ('Global' is ok but 'global' or 'GLOBAL' |
|
106 |
are not). |
|
107 |
After setting up the logger and the ConfifParser options, this function |
|
108 |
checks that mandatory sections exists ('Global'). Options are read one at a |
|
109 |
time following an internal order (not necessarily the input order). |
|
110 |
For every section, section-mandatory options are checked to be present. |
|
111 |
All the other options have a default/fallback value if the option is not |
|
112 |
specified. |
|
113 |
The values of every option are checked and errors are recorded in the |
|
114 |
program log and an exception is raised. |
|
115 |
@param in_file: str, absolute or relative path to the input file to be read. |
|
116 |
@return: return_vars: dict, list of all the input variables together with |
|
117 |
their values |
|
118 |
""" |
|
119 |
import os.path |
|
120 |
from configparser import ConfigParser, NoSectionError, NoOptionError, \ |
|
121 |
MissingSectionHeaderError, DuplicateOptionError |
|
122 |
|
|
123 |
from ase.data import chemical_symbols |
|
124 |
|
|
125 |
logger = logging.getLogger('DockOnSurf') |
|
126 |
|
|
127 |
dos_inp = ConfigParser(inline_comment_prefixes='#', |
|
128 |
empty_lines_in_values=False) |
|
129 |
|
|
130 |
new_answers = {'n': False, 'none': False, 'nay': False, |
|
131 |
'y': True, 'sí': True, 'aye': True, 'sure': True} |
|
132 |
|
|
133 |
for answer, val in new_answers.items(): |
|
134 |
dos_inp.BOOLEAN_STATES[answer] = val |
|
135 |
|
|
136 |
try: |
|
137 |
dos_inp.read(in_file) |
|
138 |
except MissingSectionHeaderError as e: |
|
139 |
logger.error('There are options in the input file without a Section ' |
|
140 |
'header') |
|
141 |
raise e |
|
142 |
except DuplicateOptionError as e: |
|
143 |
logger.error('There is an option in the input file that has been ' |
|
144 |
'specified more than once, possibly due to the lack of a ' |
|
145 |
'Section header') |
|
146 |
raise e |
|
147 |
|
|
148 |
turn_false_answers = [opt for opt in dos_inp.BOOLEAN_STATES |
|
149 |
if dos_inp.BOOLEAN_STATES[opt] is False] |
|
150 |
|
|
151 |
return_vars = {} |
|
152 |
|
|
153 |
no_sect_err = "Section '%s' not found on input file" |
|
154 |
no_opt_err = "Option '%s' not found on section '%s'" |
|
155 |
num_error = "'%s' value must be a %s" |
|
156 |
|
|
157 |
############## |
|
158 |
### Global ### |
|
159 |
############## |
|
160 |
### Mandatory options ### |
|
161 |
if not dos_inp.has_section('Global'): |
|
162 |
logger.error(no_sect_err % 'Global') |
|
163 |
raise NoSectionError('Global') |
|
164 |
|
|
165 |
# Checks whether the mandatory options 'run_type', 'code', etc. are |
|
166 |
# present in the Global section and ensures they have an adequate |
|
167 |
# value |
|
168 |
mand_opts = ['run_type', 'code', 'batch_q_sys'] |
|
169 |
for opt in mand_opts: |
|
170 |
if not dos_inp.has_option('Global', opt): |
|
171 |
logger.error(no_opt_err % (opt, 'Global')) |
|
172 |
raise NoOptionError(opt, 'Global') |
|
173 |
|
|
174 |
# run_type |
|
155 |
def get_run_type(): |
|
175 | 156 |
isolated, screening, refinement = (False, False, False) |
176 | 157 |
run_type_vals = ['isolated', 'screening', 'refinement', 'adsorption', |
177 | 158 |
'full'] |
... | ... | |
189 | 170 |
if 'full' in run_type: |
190 | 171 |
isolated, screening, refinement = (True, True, True) |
191 | 172 |
|
192 |
return_vars['isolated'] = isolated |
|
193 |
return_vars['screening'] = screening |
|
194 |
return_vars['refinement'] = refinement |
|
195 |
# end run_type |
|
173 |
return isolated, screening, refinement |
|
196 | 174 |
|
197 |
# code |
|
175 |
|
|
176 |
def get_code(): |
|
198 | 177 |
code_vals = ['cp2k'] |
199 | 178 |
check_expect_val(dos_inp.get('Global', 'code').lower(), code_vals) |
200 | 179 |
code = dos_inp.get('Global', 'code').lower() |
201 |
return_vars['code'] = code
|
|
202 |
# end code |
|
180 |
return code |
|
181 |
|
|
203 | 182 |
|
204 |
# batch_q_sys
|
|
183 |
def get_batch_q_sys():
|
|
205 | 184 |
batch_q_sys_vals = ['sge'] |
206 | 185 |
check_expect_val(dos_inp.get('Global', 'batch_q_sys').lower(), |
207 | 186 |
batch_q_sys_vals) |
208 | 187 |
batch_q_sys = dos_inp.get('Global', 'batch_q_sys').lower() |
209 |
return_vars['batch_q_sys'] = batch_q_sys |
|
210 |
# end batch_q_sys |
|
188 |
return batch_q_sys |
|
211 | 189 |
|
212 |
### Facultative options (Default value present) ### |
|
213 |
# relaunch_err
|
|
190 |
|
|
191 |
def get_relaunch_err():
|
|
214 | 192 |
relaunch_err_vals = ['geo_not_conv', 'false'] |
215 | 193 |
relaunch_err = dos_inp.get('Global', 'relaunch_err', |
216 | 194 |
fallback="False") |
217 | 195 |
if relaunch_err.lower() in turn_false_answers: |
218 |
relaunch_err = False
|
|
196 |
return False
|
|
219 | 197 |
else: |
220 | 198 |
check_expect_val(relaunch_err.lower(), relaunch_err_vals) |
221 |
return_vars['relaunch_err'] = relaunch_err |
|
222 |
# end relaunch_err |
|
199 |
return relaunch_err |
|
200 |
|
|
201 |
|
|
202 |
def get_max_qw(): |
|
203 |
err_msg = num_error % ('max_qw', 'positive integer') |
|
204 |
max_qw = try_command(dos_inp.getint, [(ValueError, err_msg)], |
|
205 |
'Global', 'max_qw', fallback=3) |
|
223 | 206 |
|
224 |
# max_qw |
|
225 |
try: |
|
226 |
max_qw = dos_inp.getint('Global', 'max_qw', fallback=3) |
|
227 |
except ValueError: |
|
228 |
logger.error(num_error % ('max_qw', 'positive integer')) |
|
229 |
raise ValueError(num_error % ('max_qw', 'positive integer')) |
|
230 | 207 |
if max_qw < 1: |
231 | 208 |
logger.error(num_error % ('max_qw', 'positive integer')) |
232 | 209 |
raise ValueError(num_error % ('max_qw', 'positive integer')) |
233 |
return_vars['max_qw'] = max_qw |
|
234 |
# end max_qw |
|
210 |
return max_qw |
|
211 |
|
|
212 |
|
|
213 |
def get_special_atoms(): |
|
214 |
from ase.data import chemical_symbols |
|
235 | 215 |
|
236 |
# special_atoms |
|
237 | 216 |
spec_at_err = '\'special_atoms\' does not have an adequate format.\n' \ |
238 | 217 |
'Adequate format: (Fe1 Fe) (O1 O)' |
239 | 218 |
special_atoms = dos_inp.get('Global', 'special_atoms', fallback="False") |
... | ... | |
265 | 244 |
continue |
266 | 245 |
if tup2[0] == tup[0]: |
267 | 246 |
label_err = f'You have specified the label {tup[0]} to ' \ |
268 |
f'more than one special atom'
|
|
247 |
f'more than one special atom' |
|
269 | 248 |
logger.error(label_err) |
270 | 249 |
raise ValueError(label_err) |
271 | 250 |
special_atoms = lst_tple |
272 |
return_vars['special_atoms'] = special_atoms |
|
273 |
# end special_atoms |
|
251 |
return special_atoms |
|
252 |
|
|
253 |
|
|
254 |
def get_isol_inp_file(): |
|
255 |
isol_inp_file = dos_inp.get('Isolated', 'isol_inp_file') |
|
256 |
if not os.path.isfile(isol_inp_file): |
|
257 |
logger.error(f'File {isol_inp_file} not found') |
|
258 |
raise FileNotFoundError(f'File {isol_inp_file} not found') |
|
259 |
return isol_inp_file |
|
260 |
|
|
261 |
|
|
262 |
def get_cluster_magns(): |
|
263 |
clust_magns_vals = ['energy', 'moi'] |
|
264 |
cluster_magns_str = dos_inp.get('Isolated', 'cluster_magns', |
|
265 |
fallback='energy') |
|
266 |
cluster_magns_str.replace(',', ' ').replace(';', ' ') |
|
267 |
cluster_magns = cluster_magns_str.split(' ') |
|
268 |
cluster_magns = [m.lower() for m in cluster_magns] |
|
269 |
for m in cluster_magns: |
|
270 |
check_expect_val(m, clust_magns_vals) |
|
271 |
return cluster_magns |
|
272 |
|
|
273 |
|
|
274 |
def get_num_conformers(): |
|
275 |
err_msg = num_error % ('num_conformers', 'positive integer') |
|
276 |
num_conformers = try_command(dos_inp.getint, [(ValueError, err_msg)], |
|
277 |
'Isolated', 'num_conformers', fallback=100) |
|
278 |
if num_conformers < 1: |
|
279 |
logger.error(err_msg) |
|
280 |
raise ValueError(err_msg) |
|
281 |
return num_conformers |
|
282 |
|
|
283 |
|
|
284 |
def get_num_prom_cand(): |
|
285 |
err_msg = num_error % ('num_prom_cand', 'positive integer') |
|
286 |
num_prom_cand = try_command(dos_inp.getint, [(ValueError, err_msg)], |
|
287 |
'Isolated', 'num_prom_cand', fallback=3) |
|
288 |
if num_prom_cand < 1: |
|
289 |
logger.error(err_msg) |
|
290 |
raise ValueError(err_msg) |
|
291 |
return num_prom_cand |
|
292 |
|
|
293 |
|
|
294 |
def get_iso_rmsd(): |
|
295 |
err_msg = num_error % ('iso_rmsd', 'positive decimal number') |
|
296 |
iso_rmsd = try_command(dos_inp.getfloat, [(ValueError, err_msg)], |
|
297 |
'Isolated', 'iso_rmsd', fallback=0.05) |
|
298 |
if iso_rmsd <= 0.0: |
|
299 |
logger.error(err_msg) |
|
300 |
raise ValueError(err_msg) |
|
301 |
return iso_rmsd |
|
302 |
|
|
303 |
|
|
304 |
def get_screen_inp_file(): |
|
305 |
screen_inp_file = dos_inp.get('Screening', 'screen_inp_file') |
|
306 |
if not os.path.isfile(screen_inp_file): |
|
307 |
logger.error(f'File {screen_inp_file} not found') |
|
308 |
raise FileNotFoundError(f'File {screen_inp_file} not found') |
|
309 |
return screen_inp_file |
|
310 |
|
|
311 |
|
|
312 |
def get_sites(): |
|
313 |
err_msg = 'The value of sites should be a list of atom numbers ' \ |
|
314 |
'(ie. positive integers) or groups of atom numbers ' \ |
|
315 |
'grouped by parentheses-like enclosers. \n' \ |
|
316 |
'eg. 128,(135 138;141) 87 {45, 68}' |
|
317 |
# Convert the string into a list of lists |
|
318 |
sites = try_command(str2lst, |
|
319 |
[(ValueError, err_msg), (AttributeError, err_msg)], |
|
320 |
dos_inp.get('Screening', 'sites')) |
|
321 |
# Check all elements of the list (of lists) are positive integers |
|
322 |
for site in sites: |
|
323 |
if type(site) is list: |
|
324 |
for atom in site: |
|
325 |
if atom < 0: |
|
326 |
logger.error(err_msg) |
|
327 |
raise ValueError(err_msg) |
|
328 |
elif type(site) is int: |
|
329 |
if site < 0: |
|
330 |
logger.error(err_msg) |
|
331 |
raise ValueError(err_msg) |
|
332 |
else: |
|
333 |
logger.error(err_msg) |
|
334 |
raise ValueError(err_msg) |
|
335 |
|
|
336 |
return sites |
|
337 |
|
|
338 |
|
|
339 |
def get_molec_ads_ctrs(): |
|
340 |
err_msg = 'The value of molec_ads_ctrs should be a list of atom' \ |
|
341 |
' numbers (ie. positive integers) or groups of atom ' \ |
|
342 |
'numbers enclosed by parentheses-like characters. \n' \ |
|
343 |
'eg. 128,(135 138;141) 87 {45, 68}' |
|
344 |
# Convert the string into a list of lists |
|
345 |
molec_ads_ctrs = try_command(str2lst, |
|
346 |
[(ValueError, err_msg), |
|
347 |
(AttributeError, err_msg)], |
|
348 |
dos_inp.get('Screening', 'molec_ads_ctrs')) |
|
349 |
# Check all elements of the list (of lists) are positive integers |
|
350 |
for ctr in molec_ads_ctrs: |
|
351 |
if type(ctr) is list: |
|
352 |
for atom in ctr: |
|
353 |
if atom < 0: |
|
354 |
logger.error(err_msg) |
|
355 |
raise ValueError(err_msg) |
|
356 |
elif type(ctr) is int: |
|
357 |
if ctr < 0: |
|
358 |
logger.error(err_msg) |
|
359 |
raise ValueError(err_msg) |
|
360 |
else: |
|
361 |
logger.error(err_msg) |
|
362 |
raise ValueError(err_msg) |
|
363 |
|
|
364 |
return molec_ads_ctrs |
|
365 |
|
|
366 |
|
|
367 |
def get_try_disso(): |
|
368 |
err_msg = "try_disso should be have a boolean value (True or False)" |
|
369 |
try_disso = try_command(dos_inp.getboolean, |
|
370 |
[(ValueError, err_msg)], |
|
371 |
'Screening', 'try_disso', fallback=False) |
|
372 |
return try_disso |
|
373 |
|
|
374 |
|
|
375 |
def get_pts_per_angle(): |
|
376 |
err_msg = num_error % ('sample_points_per_angle', |
|
377 |
'positive integer') |
|
378 |
pts_per_angle = try_command(dos_inp.getint, |
|
379 |
[(ValueError, err_msg)], |
|
380 |
'Screening', 'sample_points_per_angle', |
|
381 |
fallback=3) |
|
382 |
|
|
383 |
return pts_per_angle |
|
384 |
|
|
385 |
|
|
386 |
def get_coll_thrsld(): |
|
387 |
err_msg = num_error % ('collision_threshold', |
|
388 |
'positive decimal number') |
|
389 |
|
|
390 |
coll_thrsld = try_command(dos_inp.getfloat, |
|
391 |
[(ValueError, err_msg)], |
|
392 |
'Screening', 'collision_threshold', fallback=1.2) |
|
393 |
if coll_thrsld <= 0: |
|
394 |
logger.error(err_msg) |
|
395 |
raise ValueError(err_msg) |
|
396 |
|
|
397 |
return coll_thrsld |
|
398 |
|
|
399 |
|
|
400 |
def get_screen_rmsd(): |
|
401 |
err_msg = num_error % ('screen_rmsd', 'positive decimal number') |
|
402 |
screen_rmsd = try_command(dos_inp.getfloat, |
|
403 |
[(ValueError, err_msg)], |
|
404 |
'Screening', 'screen_rmsd', fallback=0.05) |
|
405 |
if screen_rmsd <= 0: |
|
406 |
logger.error(err_msg) |
|
407 |
raise ValueError(err_msg) |
|
408 |
|
|
409 |
return screen_rmsd |
|
410 |
|
|
411 |
|
|
412 |
def get_coll_bottom_z(): |
|
413 |
err_msg = num_error % ('collision_bottom_z', 'decimal number') |
|
414 |
coll_bottom_z = dos_inp.get('Screening', 'collision_bottom_z', |
|
415 |
fallback="False") |
|
416 |
if coll_bottom_z.lower() in turn_false_answers: |
|
417 |
coll_bottom_z = False |
|
418 |
else: |
|
419 |
try_command(float, [(ValueError, err_msg)], coll_bottom_z) |
|
420 |
|
|
421 |
return coll_bottom_z |
|
422 |
|
|
423 |
|
|
424 |
def get_refine_inp_file(): |
|
425 |
refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file') |
|
426 |
if not os.path.isfile(refine_inp_file): |
|
427 |
logger.error(f'File {refine_inp_file} not found') |
|
428 |
raise FileNotFoundError(f'File {refine_inp_file} not found') |
|
429 |
|
|
430 |
return refine_inp_file |
|
431 |
|
|
432 |
|
|
433 |
def get_energy_cutoff(): |
|
434 |
err_msg = num_error % ('energy_cutoff', 'positive decimal number') |
|
435 |
energy_cutoff = try_command(dos_inp.getfloat, |
|
436 |
[(ValueError, err_msg)], |
|
437 |
'Refinement', 'energy_cutoff', fallback=0.5) |
|
438 |
if energy_cutoff < 0: |
|
439 |
logger.error(err_msg) |
|
440 |
raise ValueError(err_msg) |
|
441 |
return energy_cutoff |
|
442 |
|
|
443 |
|
|
444 |
def read_input(in_file): |
|
445 |
err = False |
|
446 |
try: |
|
447 |
dos_inp.read(in_file) |
|
448 |
except MissingSectionHeaderError as e: |
|
449 |
logger.error('There are options in the input file without a Section ' |
|
450 |
'header') |
|
451 |
err = e |
|
452 |
except DuplicateOptionError as e: |
|
453 |
logger.error('There is an option in the input file that has been ' |
|
454 |
'specified more than once, possibly due to the lack of a ' |
|
455 |
'Section header') |
|
456 |
err = e |
|
457 |
except Exception as e: |
|
458 |
err = e |
|
459 |
else: |
|
460 |
err = False |
|
461 |
finally: |
|
462 |
if isinstance(err, BaseException): |
|
463 |
raise err |
|
274 | 464 |
|
275 |
################ |
|
276 |
### Isolated ### |
|
277 |
################ |
|
465 |
return_vars = {} |
|
466 |
|
|
467 |
# Global |
|
468 |
if not dos_inp.has_section('Global'): |
|
469 |
logger.error(no_sect_err % 'Global') |
|
470 |
raise NoSectionError('Global') |
|
471 |
|
|
472 |
# Mandatory options |
|
473 |
# Checks whether the mandatory options 'run_type', 'code', etc. are present. |
|
474 |
screen_mand_opts = ['run_type', 'code', 'batch_q_sys'] |
|
475 |
for opt in screen_mand_opts: |
|
476 |
if not dos_inp.has_option('Global', opt): |
|
477 |
logger.error(no_opt_err % (opt, 'Global')) |
|
478 |
raise NoOptionError(opt, 'Global') |
|
479 |
|
|
480 |
# Gets which sections are to be carried out |
|
481 |
isolated, screening, refinement = get_run_type() |
|
482 |
return_vars['isolated'] = isolated |
|
483 |
return_vars['screening'] = screening |
|
484 |
return_vars['refinement'] = refinement |
|
485 |
return_vars['code'] = get_code() |
|
486 |
return_vars['batch_q_sys'] = get_batch_q_sys() |
|
487 |
|
|
488 |
# Facultative options (Default/Fallback value present) |
|
489 |
return_vars['relaunch_err'] = get_relaunch_err() |
|
490 |
return_vars['max_qw'] = get_max_qw() |
|
491 |
return_vars['special_atoms'] = get_special_atoms() |
|
492 |
|
|
493 |
# Isolated |
|
278 | 494 |
if isolated: |
279 |
### Mandatory options if Isolated ### |
|
280 | 495 |
if not dos_inp.has_section('Isolated'): |
281 | 496 |
logger.error(no_sect_err % 'Isolated') |
282 | 497 |
raise NoSectionError('Isolated') |
283 |
|
|
284 |
# isol_inp_file |
|
285 |
if 'isol_inp_file' not in dos_inp.options('Isolated'): |
|
286 |
logger.error(no_opt_err % ('isol_inp_file', 'Isolated')) |
|
287 |
raise NoOptionError('isol_inp_file', 'Isolated') |
|
288 |
isol_inp_file = dos_inp.get('Isolated', 'isol_inp_file') |
|
289 |
if not os.path.isfile(isol_inp_file): |
|
290 |
logger.error(f'File {isol_inp_file} not found') |
|
291 |
raise FileNotFoundError(f'File {isol_inp_file} not found') |
|
292 |
return_vars['isol_inp_file'] = isol_inp_file |
|
293 |
# end isol_inp_file |
|
294 |
|
|
295 |
### Facultative options (Default/Fallback value present) ### |
|
296 |
# cluster_magns |
|
297 |
clust_magns_vals = ['energy', 'moi'] |
|
298 |
cluster_magns_str = dos_inp.get('Isolated', 'cluster_magns', |
|
299 |
fallback='energy') |
|
300 |
cluster_magns_str.replace(',', ' ').replace(';', ' ') |
|
301 |
cluster_magns = cluster_magns_str.split(' ') |
|
302 |
cluster_magns = [m.lower() for m in cluster_magns] |
|
303 |
for m in cluster_magns: |
|
304 |
check_expect_val(m, clust_magns_vals) |
|
305 |
return_vars['cluster_magns'] = cluster_magns |
|
306 |
# end cluster_magns |
|
307 |
|
|
308 |
# num_conformers |
|
309 |
try: |
|
310 |
num_conformers = dos_inp.getint('Isolated', 'num_conformers', |
|
311 |
fallback=100) |
|
312 |
except ValueError: |
|
313 |
logger.error(num_error % ('num_conformers', 'positive integer')) |
|
314 |
raise ValueError(num_error % ('num_conformers', 'positive integer')) |
|
315 |
if num_conformers < 1: |
|
316 |
logger.error(num_error % ('num_conformers', 'positive integer')) |
|
317 |
raise ValueError(num_error % ('num_conformers', 'positive integer')) |
|
318 |
return_vars['num_conformers'] = num_conformers |
|
319 |
# end num_conformers |
|
320 |
|
|
321 |
# num_prom_cand |
|
322 |
try: |
|
323 |
num_prom_cand = dos_inp.getint('Isolated', 'num_prom_cand', |
|
324 |
fallback=3) |
|
325 |
except ValueError: |
|
326 |
logger.error(num_error % ('num_prom_cand', 'positive integer')) |
|
327 |
raise ValueError(num_error % ('num_prom_cand', 'positive integer')) |
|
328 |
if num_prom_cand < 1: |
|
329 |
logger.error(num_error % ('num_prom_cand', 'positive integer')) |
|
330 |
raise ValueError(num_error % ('num_prom_cand', 'positive integer')) |
|
331 |
return_vars['num_prom_cand'] = num_prom_cand |
|
332 |
# end num_prom_cand |
|
333 |
|
|
334 |
# iso_rmsd |
|
335 |
try: |
|
336 |
iso_rmsd = dos_inp.getfloat('Isolated', 'iso_rmsd', |
|
337 |
fallback=0.05) |
|
338 |
except ValueError: |
|
339 |
logger.error(num_error % ('iso_rmsd', 'positive decimal number')) |
|
340 |
raise ValueError(num_error % ('iso_rmsd', 'positive decimal ' |
|
341 |
'number')) |
|
342 |
if iso_rmsd <= 0.0: |
|
343 |
logger.error(num_error % ('iso_rmsd', 'positive decimal number')) |
|
344 |
raise ValueError(num_error % ('iso_rmsd', 'positive decimal ' |
|
345 |
'number')) |
|
346 |
return_vars['iso_rmsd'] = iso_rmsd |
|
347 |
# end iso_rmsd |
|
348 |
|
|
349 |
################# |
|
350 |
### Screening ### |
|
351 |
################# |
|
498 |
# Mandatory options |
|
499 |
# Checks whether the mandatory options are present. |
|
500 |
iso_mand_opts = ['iso_inp_file'] |
|
501 |
for opt in iso_mand_opts: |
|
502 |
if not dos_inp.has_option('Isolated', opt): |
|
503 |
logger.error(no_opt_err % (opt, 'Isolated')) |
|
504 |
raise NoOptionError(opt, 'Isolated') |
|
505 |
return_vars['isol_inp_file'] = get_isol_inp_file() |
|
506 |
|
|
507 |
# Facultative options (Default/Fallback value present) |
|
508 |
return_vars['cluster_magns'] = get_cluster_magns() |
|
509 |
return_vars['num_conformers'] = get_num_conformers() |
|
510 |
return_vars['num_prom_cand'] = get_num_prom_cand() |
|
511 |
return_vars['iso_rmsd'] = get_iso_rmsd() |
|
512 |
|
|
513 |
# Screening |
|
352 | 514 |
if screening: |
353 |
### Mandatory options ### |
|
354 | 515 |
if not dos_inp.has_section('Screening'): |
355 | 516 |
logger.error(no_sect_err % 'Screening') |
356 | 517 |
raise NoSectionError('Screening') |
357 |
|
|
358 |
# screen_inp_file |
|
359 |
if 'screen_inp_file' not in dos_inp.options('Screening'): |
|
360 |
logger.error(no_opt_err % ('screen_inp_file', 'Screening')) |
|
361 |
raise NoOptionError('screen_inp_file', 'Screening') |
|
362 |
screen_inp_file = dos_inp.get('Screening', 'screen_inp_file') |
|
363 |
if not os.path.isfile(screen_inp_file): |
|
364 |
logger.error(f'File {screen_inp_file} not found') |
|
365 |
raise FileNotFoundError(f'File {screen_inp_file} not found') |
|
366 |
return_vars['screen_inp_file'] = screen_inp_file |
|
367 |
# end screen_inp_file |
|
368 |
|
|
369 |
# Checks whether the mandatory options 'sites', 'molec_ads_ctrs', etc. |
|
370 |
# are present in the Screening section |
|
371 |
mand_opts = ['sites', 'molec_ads_ctrs'] |
|
372 |
for opt in mand_opts: |
|
518 |
# Mandatory options: |
|
519 |
# Checks whether the mandatory options are present. |
|
520 |
screen_mand_opts = ['sites', 'molec_ads_ctrs', 'screen_inp_file'] |
|
521 |
for opt in screen_mand_opts: |
|
373 | 522 |
if not dos_inp.has_option('Screening', opt): |
374 | 523 |
logger.error(no_opt_err % (opt, 'Screening')) |
375 | 524 |
raise NoOptionError(opt, 'Screening') |
376 |
|
|
377 |
# sites |
|
378 |
sites_err = 'The value of sites should be a list of atom numbers ' \ |
|
379 |
'(ie. positive integers) or groups of atom numbers ' \ |
|
380 |
'grouped by parentheses-like enclosers. \n' \ |
|
381 |
'eg. 128,(135 138;141) 87 {45, 68}' |
|
382 |
try: |
|
383 |
sites = str2lst(dos_inp.get('Screening', 'sites')) |
|
384 |
except (ValueError, AttributeError): |
|
385 |
logger.error(sites_err) |
|
386 |
raise ValueError(sites_err) |
|
387 |
|
|
388 |
# Check all elements of the list (of lists) are positive integers |
|
389 |
for site in sites: |
|
390 |
if type(site) is list: |
|
391 |
for atom in site: |
|
392 |
if atom < 0: |
|
393 |
logger.error(sites_err) |
|
394 |
raise ValueError(sites_err) |
|
395 |
elif type(site) is int: |
|
396 |
if site < 0: |
|
397 |
logger.error(sites_err) |
|
398 |
raise ValueError(sites_err) |
|
399 |
else: |
|
400 |
logger.error(sites_err) |
|
401 |
raise ValueError(sites_err) |
|
402 |
return_vars['sites'] = sites |
|
403 |
# end sites |
|
404 |
|
|
405 |
# molec_ads_ctrs |
|
406 |
molec_ads_err = 'The value of molec_ads_ctrs should be a list of atom' \ |
|
407 |
' numbers (ie. positive integers) or groups of atom ' \ |
|
408 |
'numbers enclosed by parentheses-like characters. \n' \ |
|
409 |
'eg. 128,(135 138;141) 87 {45, 68}' |
|
410 |
try: |
|
411 |
molec_ads_ctrs = str2lst(dos_inp.get('Screening', 'molec_ads_ctrs')) |
|
412 |
except (ValueError, AttributeError): |
|
413 |
logger.error(molec_ads_err) |
|
414 |
raise ValueError(molec_ads_err) |
|
415 |
|
|
416 |
# Check all elements of the list (of lists) are positive integers |
|
417 |
for ctr in molec_ads_ctrs: |
|
418 |
if type(ctr) is list: |
|
419 |
for atom in ctr: |
|
420 |
if atom < 0: |
|
421 |
logger.error(molec_ads_err) |
|
422 |
raise ValueError(molec_ads_err) |
|
423 |
elif type(ctr) is int: |
|
424 |
if ctr < 0: |
|
425 |
logger.error(molec_ads_err) |
|
426 |
raise ValueError(molec_ads_err) |
|
427 |
else: |
|
428 |
logger.error(molec_ads_err) |
|
429 |
raise ValueError(molec_ads_err) |
|
430 |
return_vars['molec_ads_ctrs'] = molec_ads_ctrs |
|
431 |
# end molec_ads_ctrs |
|
432 |
|
|
433 |
### Facultative options (Default value present) ### |
|
434 |
|
|
435 |
# try_disso |
|
436 |
try: |
|
437 |
try_disso = dos_inp.getboolean('Screening', 'try_disso', |
|
438 |
fallback=False) |
|
439 |
except ValueError: |
|
440 |
disso_err = 'try_disso should be have a boolean value (True or ' \ |
|
441 |
'False) ' |
|
442 |
logger.error(disso_err) |
|
443 |
raise ValueError(disso_err) |
|
444 |
return_vars['try_disso'] = try_disso |
|
445 |
# end try_disso |
|
446 |
|
|
447 |
# sample_points_per_angle |
|
448 |
try: |
|
449 |
sample_points_per_angle = dos_inp.getint('Screening', |
|
450 |
'sample_points_per_angle', |
|
451 |
fallback=3) |
|
452 |
except ValueError: |
|
453 |
logger.error(num_error % ('sample_points_per_angle', |
|
454 |
'positive integer')) |
|
455 |
raise ValueError(num_error % ('sample_points_per_angle', |
|
456 |
'positive integer')) |
|
457 |
if sample_points_per_angle < 1: |
|
458 |
logger.error(num_error % ('sample_points_per_angle', |
|
459 |
'positive integer')) |
|
460 |
raise ValueError(num_error % ('sample_points_per_angle', |
|
461 |
'positive integer')) |
|
462 |
return_vars['sample_points_per_angle'] = sample_points_per_angle |
|
463 |
# end sample_points_per_angle |
|
464 |
|
|
465 |
# collision_threshold |
|
466 |
try: |
|
467 |
collision_threshold = dos_inp.getfloat('Screening', |
|
468 |
'collision_threshold', |
|
469 |
fallback=1.2) |
|
470 |
except ValueError: |
|
471 |
logger.error(num_error % ('collision_threshold', |
|
472 |
'positive decimal number')) |
|
473 |
raise ValueError(num_error % ('collision_threshold', |
|
474 |
'positive decimal number')) |
|
475 |
return_vars['collision_threshold'] = collision_threshold |
|
476 |
if collision_threshold <= 0: |
|
477 |
logger.error(num_error % ('collision_threshold', |
|
478 |
'positive decimal number')) |
|
479 |
raise ValueError(num_error % ('collision_threshold', |
|
480 |
'positive decimal number')) |
|
481 |
# end collision_threshold |
|
482 |
|
|
483 |
# screen_rmsd |
|
484 |
try: |
|
485 |
screen_rmsd = dos_inp.getfloat('Screening', |
|
486 |
'screen_rmsd', |
|
487 |
fallback=0.05) |
|
488 |
except ValueError: |
|
489 |
logger.error(num_error % ('screen_rmsd', 'positive decimal number')) |
|
490 |
raise ValueError(num_error % ('screen_rmsd', 'positive decimal ' |
|
491 |
'number')) |
|
492 |
if screen_rmsd <= 0: |
|
493 |
logger.error(num_error % ('screen_rmsd', 'positive decimal number')) |
|
494 |
raise ValueError(num_error % ('screen_rmsd', 'positive decimal ' |
|
495 |
'number')) |
|
496 |
return_vars['screen_rmsd'] = screen_rmsd |
|
497 |
# end screen_rmsd |
|
498 |
|
|
499 |
# collision_bottom_z |
|
500 |
collision_bottom_z = dos_inp.get('Screening', 'collision_bottom_z', |
|
501 |
fallback="False") |
|
502 |
if collision_bottom_z.lower() in turn_false_answers: |
|
503 |
collision_bottom_z = False |
|
504 |
else: |
|
505 |
try: |
|
506 |
collision_bottom_z = float(collision_bottom_z) |
|
507 |
except ValueError: |
|
508 |
logger.error(num_error % ('collision_bottom_z', |
|
509 |
'decimal number')) |
|
510 |
raise ValueError(num_error % ('collision_bottom_z', |
|
511 |
'decimal number')) |
|
512 |
return_vars['collision_bottom_z'] = collision_bottom_z |
|
513 |
# end collision_bottom_z |
|
514 |
|
|
515 |
################## |
|
516 |
### Refinement ### |
|
517 |
################## |
|
525 |
return_vars['screen_inp_file'] = get_screen_inp_file() |
|
526 |
return_vars['sites'] = get_sites() |
|
527 |
return_vars['molec_ads_ctrs'] = get_molec_ads_ctrs() |
|
528 |
|
|
529 |
# Facultative options (Default value present) |
|
530 |
return_vars['try_disso'] = get_try_disso() |
|
531 |
return_vars['sample_points_per_angle'] = get_pts_per_angle() |
|
532 |
return_vars['collision_threshold'] = get_coll_thrsld() |
|
533 |
return_vars['screen_rmsd'] = get_screen_rmsd() |
|
534 |
return_vars['collision_bottom_z'] = get_coll_bottom_z() |
|
535 |
|
|
536 |
# Refinement |
|
518 | 537 |
if refinement: |
519 |
### Mandatory options ### |
|
520 |
# refine_inp_file |
|
521 |
if 'refine_inp_file' not in dos_inp.options('Refinement'): |
|
522 |
logger.error(no_opt_err % ('refine_inp_file', 'Refinement')) |
|
523 |
raise NoOptionError('refine_inp_file', 'Refinement') |
|
524 |
refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file') |
|
525 |
if not os.path.isfile(refine_inp_file): |
|
526 |
logger.error(f'File {refine_inp_file} not found') |
|
527 |
raise FileNotFoundError(f'File {refine_inp_file} not found') |
|
528 |
return_vars['refine_inp_file'] = refine_inp_file |
|
529 |
# end refine_inp_file |
|
530 |
|
|
531 |
### Facultative options (Default value present) ### |
|
532 |
# energy_cutoff |
|
533 |
try: |
|
534 |
energy_cutoff = dos_inp.getfloat('Refinement', 'energy_cutoff', |
|
535 |
fallback=0.5) |
|
536 |
except ValueError: |
|
537 |
logger.error(num_error % ('energy_cutoff', |
|
538 |
'positive decimal number')) |
|
539 |
raise ValueError(num_error % ('energy_cutoff', |
|
540 |
'positive decimal number')) |
|
541 |
if energy_cutoff < 0: |
|
542 |
logger.error(num_error % ('energy_cutoff', |
|
543 |
'positive decimal number')) |
|
544 |
raise ValueError(num_error % ('energy_cutoff', |
|
545 |
'positive decimal number')) |
|
546 |
return_vars['energy_cutoff'] = energy_cutoff |
|
538 |
if not dos_inp.has_section('Refinement'): |
|
539 |
logger.error(no_sect_err % 'Refinement') |
|
540 |
raise NoSectionError('Refinement') |
|
541 |
# Mandatory options |
|
542 |
# Checks whether the mandatory options are present. |
|
543 |
ref_mand_opts = ['refine_inp_file'] |
|
544 |
for opt in ref_mand_opts: |
|
545 |
if not dos_inp.has_option('Refinement', opt): |
|
546 |
logger.error(no_opt_err % (opt, 'Refinement')) |
|
547 |
raise NoOptionError(opt, 'Refinement') |
|
548 |
return_vars['refine_inp_file'] = get_refine_inp_file() |
|
549 |
|
|
550 |
# Facultative options (Default value present) |
|
551 |
return_vars['energy_cutoff'] = get_energy_cutoff() |
|
547 | 552 |
# end energy_cutoff |
548 | 553 |
|
549 | 554 |
return return_vars |
555 |
|
|
556 |
|
|
557 |
if __name__ == "__main__": |
|
558 |
import sys |
|
559 |
|
|
560 |
print(read_input(sys.argv[1])) |
Formats disponibles : Unified diff