Statistiques
| Branche: | Tag: | Révision :

dockonsurf / modules / dos_input.py @ b75bf97d

Historique | Voir | Annoter | Télécharger (33,15 ko)

1 b77be9ad Carles
"""Functions to deal with DockOnSurf input files.
2 b77be9ad Carles

3 b77be9ad Carles
Functions
4 0e83e6a6 Carles
try_command:Tries to run a command and logs its exceptions (expected and not).
5 0e83e6a6 Carles
str2lst: Converts a string of integers, and groups of them, to a list of lists.
6 0e83e6a6 Carles
check_expect_val: Checks whether the value of an option has an adequate value.
7 0e83e6a6 Carles
read_input: Sets up the calculation by reading the parameters from input file.
8 0e83e6a6 Carles
get_run_type: Gets 'run_type' value and checks that its value is acceptable.
9 0e83e6a6 Carles
get_code: Gets 'code' value and checks that its value is acceptable.
10 0e83e6a6 Carles
get_batch_q_sys: Gets 'batch_q_sys' value and checks that its value is
11 8887f41d Carles
acceptable.
12 0e83e6a6 Carles
get_relaunch_err: Gets 'relaunch_err' value and checks that its value is
13 8887f41d Carles
acceptable.
14 09c3325a Carles Marti
get_max_jobs: Gets 'max_jobs' value and checks that its value is acceptable.
15 0e83e6a6 Carles
get_special_atoms: Gets 'special_atoms' value and checks that its value is
16 8887f41d Carles
acceptable.
17 0e83e6a6 Carles
get_isol_inp_file: Gets 'isol_inp_file' value and checks that its value is
18 8887f41d Carles
acceptable.
19 0e83e6a6 Carles
get_cluster_magns: Gets 'cluster_magns' value and checks that its value is
20 8887f41d Carles
acceptable.
21 0e83e6a6 Carles
get_num_conformers: Gets 'num_conformers' value and checks that its value is
22 8887f41d Carles
acceptable.
23 0e83e6a6 Carles
get_num_prom_cand: Gets 'num_prom_cand' value and checks that its value is
24 8887f41d Carles
acceptable.
25 a5c74494 Carles
get_iso_rmsd: Gets 'iso_rmsd' value and checks that its value is acceptable.
26 4670488d Carles Marti
get_pre_opt: Gets 'pre_opt' value and checks that its value is acceptable.
27 0e83e6a6 Carles
get_screen_inp_file: Gets 'screen_inp_file' value and checks that its value is
28 8887f41d Carles
acceptable.
29 0e83e6a6 Carles
get_sites: Gets 'sites' value and checks that its value is acceptable.
30 7dd94df7 Carles Marti
get_molec_ctrs: Gets 'molec_ctrs' value and checks that its value is
31 8887f41d Carles
acceptable.
32 0e83e6a6 Carles
get_try_disso: Gets 'try_disso' value and checks that its value is acceptable.
33 0e83e6a6 Carles
get_pts_per_angle: Gets 'pts_per_angle' value and checks that its value is
34 8887f41d Carles
acceptable.
35 0e83e6a6 Carles
get_coll_thrsld: Gets 'coll_thrsld' value and checks that its value is
36 8887f41d Carles
acceptable.
37 0e83e6a6 Carles
get_screen_rmsd: Gets 'screen_rmsd' value and checks that its value is
38 8887f41d Carles
acceptable.
39 0e83e6a6 Carles
get_coll_bottom_z: Gets 'coll_bottom_z' value and checks that its value is
40 8887f41d Carles
acceptable.
41 0e83e6a6 Carles
get_refine_inp_file: Gets 'refine_inp_file' value and checks that its value is
42 8887f41d Carles
acceptable.
43 0e83e6a6 Carles
get_energy_cutoff: Gets 'energy_cutoff' value and checks that its value is
44 8887f41d Carles
acceptable.
45 17e72a49 Carles
"""
46 8887f41d Carles
import os.path
47 b5b2af64 Carles
import logging
48 8887f41d Carles
from configparser import ConfigParser, NoSectionError, NoOptionError, \
49 8887f41d Carles
    MissingSectionHeaderError, DuplicateOptionError
50 5fb01677 Carles Marti
import numpy as np
51 af3e2441 Carles Marti
from modules.utilities import try_command
52 8887f41d Carles
53 8887f41d Carles
logger = logging.getLogger('DockOnSurf')
54 8887f41d Carles
55 8887f41d Carles
dos_inp = ConfigParser(inline_comment_prefixes='#',
56 8887f41d Carles
                       empty_lines_in_values=False)
57 8887f41d Carles
58 8887f41d Carles
new_answers = {'n': False, 'none': False, 'nay': False,
59 8887f41d Carles
               'y': True, '': True, 'aye': True, 'sure': True}
60 8887f41d Carles
for answer, val in new_answers.items():
61 8887f41d Carles
    dos_inp.BOOLEAN_STATES[answer] = val
62 8887f41d Carles
turn_false_answers = [answer for answer in dos_inp.BOOLEAN_STATES
63 8887f41d Carles
                      if dos_inp.BOOLEAN_STATES[answer] is False]
64 8887f41d Carles
65 8887f41d Carles
no_sect_err = "Section '%s' not found on input file"
66 8887f41d Carles
no_opt_err = "Option '%s' not found on section '%s'"
67 8887f41d Carles
num_error = "'%s' value must be a %s"
68 8887f41d Carles
69 4533134f Carles Marti
70 4533134f Carles Marti
def str2lst(cmplx_str, func=int):  # TODO: enable deeper level of nested lists
71 a7128ce1 Carles Marti
    # TODO Treat all-enclosing parenthesis as a list instead of list of lists.
72 b77be9ad Carles
    """Converts a string of integers, and groups of them, to a list.
73 b77be9ad Carles

74 b77be9ad Carles
    Keyword arguments:
75 4533134f Carles Marti
    @param cmplx_str: str, string of integers (or floats) and groups of them
76 4533134f Carles Marti
    enclosed by parentheses-like characters.
77 b77be9ad Carles
    - Group enclosers: '()' '[]' and '{}'.
78 4533134f Carles Marti
    - Separators: ',' ';' and ' '.
79 b77be9ad Carles
    - Nested groups are not allowed: '3 ((6 7) 8) 4'.
80 4533134f Carles Marti
    @param func: either to use int or float
81 b77be9ad Carles

82 4533134f Carles Marti
    @return list, list of integers (or floats), or list of integers (or floats)
83 4533134f Carles Marti
    in the case they were grouped. First, the singlets are placed, and then the
84 4533134f Carles Marti
    groups in input order.
85 b77be9ad Carles

86 b77be9ad Carles
    eg. '128,(135 138;141] 87 {45, 68}' -> [128, 87, [135, 138, 141], [45, 68]]
87 17e72a49 Carles
    """
88 b77be9ad Carles
89 8887f41d Carles
    # Checks
90 5261a07f Carles Marti
    error_msg = "Function argument should be a str, sequence of " \
91 8887f41d Carles
                "numbers separated by ',' ';' or ' '." \
92 79e3db42 Carles
                "\nThey can be grouped in parentheses-like enclosers: '()', " \
93 79e3db42 Carles
                "'[]' or {}. Nested groups are not allowed. \n" \
94 79e3db42 Carles
                "eg. 128,(135 138;141) 87 {45, 68}"
95 8887f41d Carles
    cmplx_str = try_command(cmplx_str.replace, [(AttributeError, error_msg)],
96 8887f41d Carles
                            ',', ' ')
97 8887f41d Carles
98 8887f41d Carles
    cmplx_str = cmplx_str.replace(';', ' ').replace('[', '(').replace(
99 8887f41d Carles
        ']', ')').replace('{', '(').replace('}', ')')
100 8887f41d Carles
101 4533134f Carles Marti
    try_command(list, [(ValueError, error_msg)], map(func, cmplx_str.replace(
102 8887f41d Carles
        ')', '').replace('(', '').split()))
103 8887f41d Carles
104 b5b2af64 Carles
    deepness = 0
105 b5b2af64 Carles
    for el in cmplx_str.split():
106 b5b2af64 Carles
        if '(' in el:
107 b5b2af64 Carles
            deepness += 1
108 b5b2af64 Carles
        if ')' in el:
109 b5b2af64 Carles
            deepness += -1
110 b5b2af64 Carles
        if deepness > 1 or deepness < 0:
111 9f7bb440 Carles
            logger.error(error_msg)
112 b5b2af64 Carles
            raise ValueError(error_msg)
113 17e72a49 Carles
114 772b40e5 Carles
    init_list = cmplx_str.split()
115 772b40e5 Carles
    start_group = []
116 772b40e5 Carles
    end_group = []
117 772b40e5 Carles
    for i, element in enumerate(init_list):
118 73402e22 Carles
        if '(' in element:
119 772b40e5 Carles
            start_group.append(i)
120 17e72a49 Carles
            init_list[i] = element.replace('(', '')
121 73402e22 Carles
        if ')' in element:
122 772b40e5 Carles
            end_group.append(i)
123 17e72a49 Carles
            init_list[i] = element.replace(')', '')
124 772b40e5 Carles
125 4533134f Carles Marti
    init_list = list(map(func, init_list))
126 772b40e5 Carles
127 17e72a49 Carles
    new_list = []
128 772b40e5 Carles
    for start_el, end_el in zip(start_group, end_group):
129 17e72a49 Carles
        new_list.append(init_list[start_el:end_el + 1])
130 772b40e5 Carles
131 772b40e5 Carles
    for v in new_list:
132 772b40e5 Carles
        for el in v:
133 772b40e5 Carles
            init_list.remove(el)
134 772b40e5 Carles
    return init_list + new_list
135 772b40e5 Carles
136 17e72a49 Carles
137 5f9f1400 Carles Marti
def check_expect_val(value, expect_vals, err_msg=None):
138 b77be9ad Carles
    """Checks whether an option lies within its expected values.
139 b77be9ad Carles

140 b77be9ad Carles
    Keyword arguments:
141 b77be9ad Carles
    @param value: The variable to check if its value lies within the expected
142 b77be9ad Carles
    ones
143 b77be9ad Carles
    @param expect_vals: list, list of values allowed for the present option.
144 5f9f1400 Carles Marti
    @param err_msg: The error message to be prompted in both log and screen.
145 b77be9ad Carles
    @raise ValueError: if the value is not among the expected ones.
146 b77be9ad Carles
    @return True if the value is among the expected ones.
147 b77be9ad Carles
    """
148 5f9f1400 Carles Marti
    if err_msg is None:
149 5f9f1400 Carles Marti
        err_msg = f"'{value}' is not an adequate value.\n" \
150 5f9f1400 Carles Marti
                  f"Adequate values: {expect_vals}"
151 821dca42 Carles Marti
    if not any([exp_val == value for exp_val in expect_vals]):
152 5f9f1400 Carles Marti
        logger.error(err_msg)
153 5f9f1400 Carles Marti
        raise ValueError(err_msg)
154 b77be9ad Carles
155 b77be9ad Carles
    return True
156 b77be9ad Carles
157 b77be9ad Carles
158 03fab2dd Carles
def check_inp_file(inp_file, code):
159 03fab2dd Carles
    if code == 'cp2k':
160 03fab2dd Carles
        from pycp2k import CP2K
161 03fab2dd Carles
        cp2k = CP2K()
162 03fab2dd Carles
        try_command(cp2k.parse,
163 03fab2dd Carles
                    [(UnboundLocalError, "Invalid CP2K input file")], inp_file)
164 03fab2dd Carles
165 03fab2dd Carles
166 a7128ce1 Carles Marti
# Global
167 a7128ce1 Carles Marti
168 8887f41d Carles
def get_run_type():
169 b1d27be5 Carles
    isolated, screening, refinement = (False, False, False)
170 5cc4994b Carles
    run_type_vals = ['isolated', 'screening', 'refinement', 'adsorption',
171 5cc4994b Carles
                     'full']
172 081548a0 Carles Marti
    run_types = dos_inp.get('Global', 'run_type').split()
173 081548a0 Carles Marti
    for run_type in run_types:
174 081548a0 Carles Marti
        check_expect_val(run_type.lower(), run_type_vals)
175 081548a0 Carles Marti
        if 'isol' in run_type.lower():
176 081548a0 Carles Marti
            isolated = True
177 081548a0 Carles Marti
        if 'screen' in run_type.lower():
178 081548a0 Carles Marti
            screening = True
179 081548a0 Carles Marti
        if 'refine' in run_type.lower():
180 081548a0 Carles Marti
            refinement = True
181 081548a0 Carles Marti
        if 'adsor' in run_type.lower():
182 081548a0 Carles Marti
            screening, refinement = (True, True)
183 081548a0 Carles Marti
        if 'full' in run_type.lower():
184 081548a0 Carles Marti
            isolated, screening, refinement = (True, True, True)
185 5cc4994b Carles
186 8887f41d Carles
    return isolated, screening, refinement
187 17e72a49 Carles
188 8887f41d Carles
189 8887f41d Carles
def get_code():
190 772b40e5 Carles
    code_vals = ['cp2k']
191 5cc4994b Carles
    check_expect_val(dos_inp.get('Global', 'code').lower(), code_vals)
192 5cc4994b Carles
    code = dos_inp.get('Global', 'code').lower()
193 8887f41d Carles
    return code
194 8887f41d Carles
195 17e72a49 Carles
196 8887f41d Carles
def get_batch_q_sys():
197 ec5bba46 Carles Marti
    batch_q_sys_vals = ['sge', 'lsf', 'irene', 'local'] + turn_false_answers
198 5cc4994b Carles
    check_expect_val(dos_inp.get('Global', 'batch_q_sys').lower(),
199 5cc4994b Carles
                     batch_q_sys_vals)
200 5cc4994b Carles
    batch_q_sys = dos_inp.get('Global', 'batch_q_sys').lower()
201 821dca42 Carles Marti
    if batch_q_sys.lower() in turn_false_answers:
202 821dca42 Carles Marti
        return False
203 821dca42 Carles Marti
    else:
204 821dca42 Carles Marti
        return batch_q_sys
205 17e72a49 Carles
206 8887f41d Carles
207 99afde40 Carles
def get_subm_script():
208 99afde40 Carles
    subm_script = dos_inp.get('Global', 'subm_script', fallback=False)
209 99afde40 Carles
    if subm_script and not os.path.isfile(subm_script):
210 695dcff8 Carles Marti
        logger.error(f'File {subm_script} not found.')
211 99afde40 Carles
        raise FileNotFoundError(f'File {subm_script} not found')
212 99afde40 Carles
    return subm_script
213 99afde40 Carles
214 99afde40 Carles
215 99afde40 Carles
def get_project_name():
216 bd573212 Carles
    project_name = dos_inp.get('Global', 'project_name', fallback='')
217 99afde40 Carles
    return project_name
218 99afde40 Carles
219 99afde40 Carles
220 8887f41d Carles
def get_relaunch_err():
221 09c3325a Carles Marti
    relaunch_err_vals = ['geo_not_conv']
222 b1d27be5 Carles
    relaunch_err = dos_inp.get('Global', 'relaunch_err',
223 17e72a49 Carles
                               fallback="False")
224 b1d27be5 Carles
    if relaunch_err.lower() in turn_false_answers:
225 8887f41d Carles
        return False
226 79e3db42 Carles
    else:
227 79e3db42 Carles
        check_expect_val(relaunch_err.lower(), relaunch_err_vals)
228 8887f41d Carles
    return relaunch_err
229 8887f41d Carles
230 8887f41d Carles
231 09c3325a Carles Marti
def get_max_jobs():
232 b6b1b03e Carles Marti
    import re
233 b6b1b03e Carles Marti
    err_msg = "'max_jobs' must be a list of, number plus 'p', 'q' or 'r', or " \
234 b6b1b03e Carles Marti
              "a combination of them without repeating letters.\n" \
235 b6b1b03e Carles Marti
              "eg: '2r 3p 4pr', '5q' or '3r 3p'"
236 b6b1b03e Carles Marti
    max_jobs_str = dos_inp.get('Global', 'max_jobs', fallback="inf").lower()
237 b6b1b03e Carles Marti
    str_vals = ["r", "p", "q", "rp", "rq", "pr", "qr"]
238 b6b1b03e Carles Marti
    max_jobs = {"r": np.inf, "p": np.inf, "rp": np.inf}
239 b6b1b03e Carles Marti
    if "inf" == max_jobs_str:
240 b6b1b03e Carles Marti
        return {"r": np.inf, "p": np.inf, "rp": np.inf}
241 b6b1b03e Carles Marti
    # Iterate over the number of requirements:
242 b6b1b03e Carles Marti
    for req in max_jobs_str.split():
243 b6b1b03e Carles Marti
        # Split numbers from letters into a list
244 b6b1b03e Carles Marti
        req_parts = re.findall(r'[a-z]+|\d+', req)
245 b6b1b03e Carles Marti
        if len(req_parts) != 2:
246 b6b1b03e Carles Marti
            logger.error(err_msg)
247 b6b1b03e Carles Marti
            raise ValueError(err_msg)
248 b6b1b03e Carles Marti
        if req_parts[0].isdecimal():
249 b6b1b03e Carles Marti
            req_parts[1] = req_parts[1].replace('q', 'p').replace('pr', 'rp')
250 b6b1b03e Carles Marti
            if req_parts[1] in str_vals and max_jobs[req_parts[1]] == np.inf:
251 b6b1b03e Carles Marti
                max_jobs[req_parts[1]] = int(req_parts[0])
252 b6b1b03e Carles Marti
        elif req_parts[1].isdecimal():
253 b6b1b03e Carles Marti
            req_parts[0] = req_parts[0].replace('q', 'p').replace('pr', 'rp')
254 b6b1b03e Carles Marti
            if req_parts[0] in str_vals and max_jobs[req_parts[0]] == np.inf:
255 b6b1b03e Carles Marti
                max_jobs[req_parts[0]] = int(req_parts[1])
256 b6b1b03e Carles Marti
        else:
257 b6b1b03e Carles Marti
            logger.error(err_msg)
258 b6b1b03e Carles Marti
            raise ValueError(err_msg)
259 09c3325a Carles Marti
260 09c3325a Carles Marti
    return max_jobs
261 09c3325a Carles Marti
262 09c3325a Carles Marti
263 8887f41d Carles
def get_special_atoms():
264 8887f41d Carles
    from ase.data import chemical_symbols
265 17e72a49 Carles
266 5cc4994b Carles
    spec_at_err = '\'special_atoms\' does not have an adequate format.\n' \
267 5cc4994b Carles
                  'Adequate format: (Fe1 Fe) (O1 O)'
268 5cc4994b Carles
    special_atoms = dos_inp.get('Global', 'special_atoms', fallback="False")
269 b1d27be5 Carles
    if special_atoms.lower() in turn_false_answers:
270 90819cc3 Carles Marti
        special_atoms = []
271 b1d27be5 Carles
    else:
272 8949edd0 Carles
        # Converts the string into a list of tuples
273 8949edd0 Carles
        lst_tple = [tuple(pair.replace("(", "").split()) for pair in
274 b1d27be5 Carles
                    special_atoms.split(")")[:-1]]
275 5cc4994b Carles
        if len(lst_tple) == 0:
276 9f7bb440 Carles
            logger.error(spec_at_err)
277 5cc4994b Carles
            raise ValueError(spec_at_err)
278 9f7bb440 Carles
        for i, tup in enumerate(lst_tple):
279 90819cc3 Carles Marti
            if not isinstance(tup, tuple) or len(tup) != 2:
280 9f7bb440 Carles
                logger.error(spec_at_err)
281 5cc4994b Carles
                raise ValueError(spec_at_err)
282 5cc4994b Carles
            if tup[1].capitalize() not in chemical_symbols:
283 5cc4994b Carles
                elem_err = "The second element of the couple should be an " \
284 9f7bb440 Carles
                           "actual element of the periodic table"
285 9f7bb440 Carles
                logger.error(elem_err)
286 5cc4994b Carles
                raise ValueError(elem_err)
287 9f7bb440 Carles
            if tup[0].capitalize() in chemical_symbols:
288 9f7bb440 Carles
                elem_err = "The first element of the couple is already an " \
289 9f7bb440 Carles
                           "actual element of the periodic table, "
290 9f7bb440 Carles
                logger.error(elem_err)
291 9f7bb440 Carles
                raise ValueError(elem_err)
292 9f7bb440 Carles
            for j, tup2 in enumerate(lst_tple):
293 9f7bb440 Carles
                if j <= i:
294 9f7bb440 Carles
                    continue
295 9f7bb440 Carles
                if tup2[0] == tup[0]:
296 9f7bb440 Carles
                    label_err = f'You have specified the label {tup[0]} to ' \
297 8887f41d Carles
                                f'more than one special atom'
298 9f7bb440 Carles
                    logger.error(label_err)
299 9f7bb440 Carles
                    raise ValueError(label_err)
300 b1d27be5 Carles
        special_atoms = lst_tple
301 8887f41d Carles
    return special_atoms
302 8887f41d Carles
303 8887f41d Carles
304 a7128ce1 Carles Marti
# Isolated
305 a7128ce1 Carles Marti
306 8887f41d Carles
def get_isol_inp_file():
307 8887f41d Carles
    isol_inp_file = dos_inp.get('Isolated', 'isol_inp_file')
308 8887f41d Carles
    if not os.path.isfile(isol_inp_file):
309 695dcff8 Carles Marti
        logger.error(f'File {isol_inp_file} not found.')
310 8887f41d Carles
        raise FileNotFoundError(f'File {isol_inp_file} not found')
311 8887f41d Carles
    return isol_inp_file
312 8887f41d Carles
313 8887f41d Carles
314 95dc2c8e Carles
def get_molec_file():
315 95dc2c8e Carles
    molec_file = dos_inp.get('Isolated', 'molec_file')
316 95dc2c8e Carles
    if not os.path.isfile(molec_file):
317 695dcff8 Carles Marti
        logger.error(f'File {molec_file} not found.')
318 95dc2c8e Carles
        raise FileNotFoundError(f'File {molec_file} not found')
319 95dc2c8e Carles
    return molec_file
320 95dc2c8e Carles
321 95dc2c8e Carles
322 8887f41d Carles
def get_num_conformers():
323 8887f41d Carles
    err_msg = num_error % ('num_conformers', 'positive integer')
324 8887f41d Carles
    num_conformers = try_command(dos_inp.getint, [(ValueError, err_msg)],
325 8887f41d Carles
                                 'Isolated', 'num_conformers', fallback=100)
326 8887f41d Carles
    if num_conformers < 1:
327 8887f41d Carles
        logger.error(err_msg)
328 8887f41d Carles
        raise ValueError(err_msg)
329 8887f41d Carles
    return num_conformers
330 8887f41d Carles
331 8887f41d Carles
332 4670488d Carles Marti
def get_pre_opt():
333 4670488d Carles Marti
    pre_opt_vals = ['uff', 'mmff'] + turn_false_answers
334 4670488d Carles Marti
    check_expect_val(dos_inp.get('Isolated', 'pre_opt').lower(), pre_opt_vals)
335 ad57fd42 Carles Marti
    pre_opt = dos_inp.get('Isolated', 'pre_opt').lower()
336 ad57fd42 Carles Marti
    if pre_opt in turn_false_answers:
337 4670488d Carles Marti
        return False
338 4670488d Carles Marti
    else:
339 4670488d Carles Marti
        return pre_opt
340 b1f6e69d Carles
341 70fa4e74 Carles Marti
342 a7128ce1 Carles Marti
# Screening
343 a7128ce1 Carles Marti
344 8887f41d Carles
def get_screen_inp_file():
345 8887f41d Carles
    screen_inp_file = dos_inp.get('Screening', 'screen_inp_file')
346 8887f41d Carles
    if not os.path.isfile(screen_inp_file):
347 695dcff8 Carles Marti
        logger.error(f'File {screen_inp_file} not found.')
348 8887f41d Carles
        raise FileNotFoundError(f'File {screen_inp_file} not found')
349 8887f41d Carles
    return screen_inp_file
350 8887f41d Carles
351 8887f41d Carles
352 a765b11c Carles Marti
def get_surf_file():
353 a765b11c Carles Marti
    surf_file = dos_inp.get('Screening', 'surf_file')
354 a765b11c Carles Marti
    if not os.path.isfile(surf_file):
355 695dcff8 Carles Marti
        logger.error(f'File {surf_file} not found.')
356 a765b11c Carles Marti
        raise FileNotFoundError(f'File {surf_file} not found')
357 a765b11c Carles Marti
    return surf_file
358 a765b11c Carles Marti
359 a765b11c Carles Marti
360 8887f41d Carles
def get_sites():
361 8887f41d Carles
    err_msg = 'The value of sites should be a list of atom numbers ' \
362 8887f41d Carles
              '(ie. positive integers) or groups of atom numbers ' \
363 8887f41d Carles
              'grouped by parentheses-like enclosers. \n' \
364 8887f41d Carles
              'eg. 128,(135 138;141) 87 {45, 68}'
365 8887f41d Carles
    # Convert the string into a list of lists
366 8887f41d Carles
    sites = try_command(str2lst,
367 8887f41d Carles
                        [(ValueError, err_msg), (AttributeError, err_msg)],
368 8887f41d Carles
                        dos_inp.get('Screening', 'sites'))
369 8887f41d Carles
    # Check all elements of the list (of lists) are positive integers
370 8887f41d Carles
    for site in sites:
371 8887f41d Carles
        if type(site) is list:
372 8887f41d Carles
            for atom in site:
373 8887f41d Carles
                if atom < 0:
374 8887f41d Carles
                    logger.error(err_msg)
375 8887f41d Carles
                    raise ValueError(err_msg)
376 8887f41d Carles
        elif type(site) is int:
377 8887f41d Carles
            if site < 0:
378 8887f41d Carles
                logger.error(err_msg)
379 8887f41d Carles
                raise ValueError(err_msg)
380 8887f41d Carles
        else:
381 8887f41d Carles
            logger.error(err_msg)
382 8887f41d Carles
            raise ValueError(err_msg)
383 8887f41d Carles
384 8887f41d Carles
    return sites
385 8887f41d Carles
386 8887f41d Carles
387 7dd94df7 Carles Marti
def get_surf_ctrs2():
388 7dd94df7 Carles Marti
    err_msg = 'The value of surf_ctrs2 should be a list of atom numbers ' \
389 7dd94df7 Carles Marti
              '(ie. positive integers) or groups of atom numbers ' \
390 7dd94df7 Carles Marti
              'grouped by parentheses-like enclosers. \n' \
391 7dd94df7 Carles Marti
              'eg. 128,(135 138;141) 87 {45, 68}'
392 7dd94df7 Carles Marti
    # Convert the string into a list of lists
393 7dd94df7 Carles Marti
    surf_ctrs2 = try_command(str2lst,
394 7dd94df7 Carles Marti
                             [(ValueError, err_msg), (AttributeError, err_msg)],
395 7dd94df7 Carles Marti
                             dos_inp.get('Screening', 'surf_ctrs2'))
396 7dd94df7 Carles Marti
    # Check all elements of the list (of lists) are positive integers
397 7dd94df7 Carles Marti
    for ctr in surf_ctrs2:
398 7dd94df7 Carles Marti
        if type(ctr) is list:
399 7dd94df7 Carles Marti
            for atom in ctr:
400 7dd94df7 Carles Marti
                if atom < 0:
401 7dd94df7 Carles Marti
                    logger.error(err_msg)
402 7dd94df7 Carles Marti
                    raise ValueError(err_msg)
403 7dd94df7 Carles Marti
        elif type(ctr) is int:
404 7dd94df7 Carles Marti
            if ctr < 0:
405 7dd94df7 Carles Marti
                logger.error(err_msg)
406 7dd94df7 Carles Marti
                raise ValueError(err_msg)
407 7dd94df7 Carles Marti
        else:
408 7dd94df7 Carles Marti
            logger.error(err_msg)
409 7dd94df7 Carles Marti
            raise ValueError(err_msg)
410 7dd94df7 Carles Marti
411 7dd94df7 Carles Marti
    return surf_ctrs2
412 7dd94df7 Carles Marti
413 7dd94df7 Carles Marti
414 7dd94df7 Carles Marti
def get_molec_ctrs():
415 7dd94df7 Carles Marti
    err_msg = 'The value of molec_ctrs should be a list of atom' \
416 8887f41d Carles
              ' numbers (ie. positive integers) or groups of atom ' \
417 8887f41d Carles
              'numbers enclosed by parentheses-like characters. \n' \
418 8887f41d Carles
              'eg. 128,(135 138;141) 87 {45, 68}'
419 8887f41d Carles
    # Convert the string into a list of lists
420 7dd94df7 Carles Marti
    molec_ctrs = try_command(str2lst,
421 7dd94df7 Carles Marti
                             [(ValueError, err_msg),
422 7dd94df7 Carles Marti
                              (AttributeError, err_msg)],
423 7dd94df7 Carles Marti
                             dos_inp.get('Screening', 'molec_ctrs'))
424 7dd94df7 Carles Marti
    # Check all elements of the list (of lists) are positive integers
425 7dd94df7 Carles Marti
    for ctr in molec_ctrs:
426 7dd94df7 Carles Marti
        if isinstance(ctr, list):
427 7dd94df7 Carles Marti
            for atom in ctr:
428 7dd94df7 Carles Marti
                if atom < 0:
429 7dd94df7 Carles Marti
                    logger.error(err_msg)
430 7dd94df7 Carles Marti
                    raise ValueError(err_msg)
431 7dd94df7 Carles Marti
        elif isinstance(ctr, int):
432 7dd94df7 Carles Marti
            if ctr < 0:
433 7dd94df7 Carles Marti
                logger.error(err_msg)
434 7dd94df7 Carles Marti
                raise ValueError(err_msg)
435 7dd94df7 Carles Marti
        else:
436 7dd94df7 Carles Marti
            logger.error(err_msg)
437 7dd94df7 Carles Marti
            raise ValueError(err_msg)
438 7dd94df7 Carles Marti
439 7dd94df7 Carles Marti
    return molec_ctrs
440 7dd94df7 Carles Marti
441 7dd94df7 Carles Marti
442 7dd94df7 Carles Marti
def get_molec_ctrs2():
443 7dd94df7 Carles Marti
    err_msg = 'The value of molec_ctrs2 should be a list of atom ' \
444 7dd94df7 Carles Marti
              'numbers (ie. positive integers) or groups of atom ' \
445 7dd94df7 Carles Marti
              'numbers enclosed by parentheses-like characters. \n' \
446 7dd94df7 Carles Marti
              'eg. 128,(135 138;141) 87 {45, 68}'
447 7dd94df7 Carles Marti
    # Convert the string into a list of lists
448 7dd94df7 Carles Marti
    molec_ctrs2 = try_command(str2lst, [(ValueError, err_msg),
449 7dd94df7 Carles Marti
                                        (AttributeError, err_msg)],
450 7dd94df7 Carles Marti
                              dos_inp.get('Screening', 'molec_ctrs2'))
451 7dd94df7 Carles Marti
452 8887f41d Carles
    # Check all elements of the list (of lists) are positive integers
453 7dd94df7 Carles Marti
    for ctr in molec_ctrs2:
454 c845c6f2 Carles Marti
        if isinstance(ctr, list):
455 8887f41d Carles
            for atom in ctr:
456 8887f41d Carles
                if atom < 0:
457 8887f41d Carles
                    logger.error(err_msg)
458 8887f41d Carles
                    raise ValueError(err_msg)
459 c845c6f2 Carles Marti
        elif isinstance(ctr, int):
460 8887f41d Carles
            if ctr < 0:
461 8887f41d Carles
                logger.error(err_msg)
462 8887f41d Carles
                raise ValueError(err_msg)
463 8887f41d Carles
        else:
464 8887f41d Carles
            logger.error(err_msg)
465 8887f41d Carles
            raise ValueError(err_msg)
466 8887f41d Carles
467 7dd94df7 Carles Marti
    return molec_ctrs2
468 8887f41d Carles
469 8887f41d Carles
470 7dd94df7 Carles Marti
def get_molec_ctrs3():
471 7dd94df7 Carles Marti
    err_msg = 'The value of molec_ctrs3 should be a list of atom ' \
472 c845c6f2 Carles Marti
              'numbers (ie. positive integers) or groups of atom ' \
473 c845c6f2 Carles Marti
              'numbers enclosed by parentheses-like characters. \n' \
474 c845c6f2 Carles Marti
              'eg. 128,(135 138;141) 87 {45, 68}'
475 c845c6f2 Carles Marti
    # Convert the string into a list of lists
476 7dd94df7 Carles Marti
    molec_ctrs3 = try_command(str2lst, [(ValueError, err_msg),
477 7dd94df7 Carles Marti
                                        (AttributeError, err_msg)],
478 7dd94df7 Carles Marti
                              dos_inp.get('Screening', 'molec_ctrs3'))
479 c845c6f2 Carles Marti
480 c845c6f2 Carles Marti
    # Check all elements of the list (of lists) are positive integers
481 7dd94df7 Carles Marti
    for ctr in molec_ctrs3:
482 c845c6f2 Carles Marti
        if isinstance(ctr, list):
483 c845c6f2 Carles Marti
            for atom in ctr:
484 c845c6f2 Carles Marti
                if atom < 0:
485 c845c6f2 Carles Marti
                    logger.error(err_msg)
486 c845c6f2 Carles Marti
                    raise ValueError(err_msg)
487 c845c6f2 Carles Marti
        elif isinstance(ctr, int):
488 c845c6f2 Carles Marti
            if ctr < 0:
489 c845c6f2 Carles Marti
                logger.error(err_msg)
490 c845c6f2 Carles Marti
                raise ValueError(err_msg)
491 c845c6f2 Carles Marti
        else:
492 c845c6f2 Carles Marti
            logger.error(err_msg)
493 c845c6f2 Carles Marti
            raise ValueError(err_msg)
494 c845c6f2 Carles Marti
495 7dd94df7 Carles Marti
    return molec_ctrs3
496 c845c6f2 Carles Marti
497 c845c6f2 Carles Marti
498 a98d4172 Carles Marti
def get_max_helic_angle():
499 a98d4172 Carles Marti
    err_msg = "'max_helic_angle' must be a positive number in degrees"
500 a98d4172 Carles Marti
    max_helic_angle = try_command(dos_inp.getfloat, [(ValueError, err_msg)],
501 a98d4172 Carles Marti
                                  'Screening', 'max_helic_angle',
502 a98d4172 Carles Marti
                                  fallback=180.0)
503 a98d4172 Carles Marti
    if max_helic_angle < 0:
504 a98d4172 Carles Marti
        logger.error(err_msg)
505 a98d4172 Carles Marti
        raise ValueError(err_msg)
506 a98d4172 Carles Marti
507 a98d4172 Carles Marti
    return max_helic_angle
508 a98d4172 Carles Marti
509 a98d4172 Carles Marti
510 8af49f6d Carles Marti
def get_select_magns():
511 8af49f6d Carles Marti
    select_magns_vals = ['energy', 'moi']
512 8af49f6d Carles Marti
    select_magns_str = dos_inp.get('Screening', 'select_magns',
513 af2bf62f Carles Marti
                                   fallback='energy')
514 8af49f6d Carles Marti
    select_magns_str.replace(',', ' ').replace(';', ' ')
515 8af49f6d Carles Marti
    select_magns = select_magns_str.split(' ')
516 8af49f6d Carles Marti
    select_magns = [m.lower() for m in select_magns]
517 8af49f6d Carles Marti
    for m in select_magns:
518 8af49f6d Carles Marti
        check_expect_val(m, select_magns_vals)
519 8af49f6d Carles Marti
    return select_magns
520 8af49f6d Carles Marti
521 8af49f6d Carles Marti
522 af2bf62f Carles Marti
def get_confs_per_magn():
523 af2bf62f Carles Marti
    err_msg = num_error % ('confs_per_magn', 'positive integer')
524 af2bf62f Carles Marti
    confs_per_magn = try_command(dos_inp.getint, [(ValueError, err_msg)],
525 af2bf62f Carles Marti
                                 'Screening', 'confs_per_magn', fallback=2)
526 af2bf62f Carles Marti
    if confs_per_magn <= 0:
527 af2bf62f Carles Marti
        logger.error(err_msg)
528 af2bf62f Carles Marti
        raise ValueError(err_msg)
529 af2bf62f Carles Marti
    return confs_per_magn
530 af2bf62f Carles Marti
531 af2bf62f Carles Marti
532 bc703cab Carles Marti
def get_pbc_cell():
533 bc703cab Carles Marti
    err = "'pbc_cell' must be either 3 vectors of size 3 or False"
534 bc703cab Carles Marti
    pbc_cell_str = dos_inp.get('Screening', 'pbc_cell', fallback="False")
535 bc703cab Carles Marti
    if pbc_cell_str.lower() in turn_false_answers:
536 bc703cab Carles Marti
        return False
537 bc703cab Carles Marti
    else:
538 bc703cab Carles Marti
        pbc_cell = np.array(try_command(str2lst, [(ValueError, err)],
539 bc703cab Carles Marti
                                        pbc_cell_str, float))
540 bc703cab Carles Marti
        if pbc_cell.shape != (3, 3):
541 bc703cab Carles Marti
            logger.error(err)
542 bc703cab Carles Marti
            raise ValueError(err)
543 bc703cab Carles Marti
        return pbc_cell
544 bc703cab Carles Marti
545 bc703cab Carles Marti
546 c845c6f2 Carles Marti
def get_surf_norm_vect():
547 d6da8693 Carles Marti
    err = "'surf_norm_vect' must be a 3 component vector, 'x', 'y' or 'z', " \
548 d6da8693 Carles Marti
          "'auto' or 'asann'."
549 9c16a7e2 Carles Marti
    cart_axes = {'x': [1.0, 0.0, 0.0], '-x': [-1.0, 0.0, 0.0],
550 9c16a7e2 Carles Marti
                 'y': [0.0, 1.0, 0.0], '-y': [0.0, -1.0, 0.0],
551 9c16a7e2 Carles Marti
                 'z': [0.0, 0.0, 1.0], '-z': [0.0, 0.0, -1.0]}
552 c845c6f2 Carles Marti
    surf_norm_vect_str = dos_inp.get('Screening', 'surf_norm_vect',
553 d6da8693 Carles Marti
                                     fallback="auto").lower()
554 d6da8693 Carles Marti
    if surf_norm_vect_str == "asann" or surf_norm_vect_str == "auto":
555 d6da8693 Carles Marti
        return 'auto'
556 9c16a7e2 Carles Marti
    if surf_norm_vect_str in cart_axes:
557 d6da8693 Carles Marti
        return np.array(cart_axes[surf_norm_vect_str])
558 d6da8693 Carles Marti
    surf_norm_vect = try_command(str2lst, [(ValueError, err)],
559 d6da8693 Carles Marti
                                 surf_norm_vect_str, float)
560 d6da8693 Carles Marti
    if len(surf_norm_vect) != 3:
561 d6da8693 Carles Marti
        logger.error(err)
562 d6da8693 Carles Marti
        raise ValueError(err)
563 3d56e566 Carles Marti
564 b6b1b03e Carles Marti
    return np.array(surf_norm_vect) / np.linalg.norm(surf_norm_vect)
565 c845c6f2 Carles Marti
566 c845c6f2 Carles Marti
567 7dd94df7 Carles Marti
def get_set_angles():
568 7dd94df7 Carles Marti
    set_vals = ['euler', 'chemcat']
569 7dd94df7 Carles Marti
    check_expect_val(dos_inp.get('Screening', 'set_angles').lower(), set_vals)
570 5261a07f Carles Marti
    set_angles = dos_inp.get('Screening', 'set_angles',
571 5261a07f Carles Marti
                             fallback='euler').lower()
572 7dd94df7 Carles Marti
    return set_angles
573 a7c7b43e Carles Marti
574 a7c7b43e Carles Marti
575 8887f41d Carles
def get_pts_per_angle():
576 d4bedc18 Carles Marti
    err_msg = num_error % ('sample_points_per_angle', 'positive integer')
577 8887f41d Carles
    pts_per_angle = try_command(dos_inp.getint,
578 8887f41d Carles
                                [(ValueError, err_msg)],
579 8887f41d Carles
                                'Screening', 'sample_points_per_angle',
580 8887f41d Carles
                                fallback=3)
581 d4bedc18 Carles Marti
    if pts_per_angle <= 0:
582 d4bedc18 Carles Marti
        logger.error(err_msg)
583 d4bedc18 Carles Marti
        raise ValueError(err_msg)
584 8887f41d Carles
    return pts_per_angle
585 8887f41d Carles
586 8887f41d Carles
587 7d97341d Carles Marti
def get_max_structures():
588 7d97341d Carles Marti
    err_msg = num_error % ('max_structures', 'positive integer')
589 21209d96 Carles Marti
    max_structs = dos_inp.get('Screening', 'max_structures', fallback="False")
590 21209d96 Carles Marti
    if max_structs.lower() in turn_false_answers:
591 21209d96 Carles Marti
        return np.inf
592 21209d96 Carles Marti
    if try_command(int, [(ValueError, err_msg)], max_structs) <= 0:
593 7d97341d Carles Marti
        logger.error(err_msg)
594 7d97341d Carles Marti
        raise ValueError(err_msg)
595 21209d96 Carles Marti
    return int(max_structs)
596 7d97341d Carles Marti
597 7d97341d Carles Marti
598 8887f41d Carles
def get_coll_thrsld():
599 8887f41d Carles
    err_msg = num_error % ('collision_threshold',
600 eef995b8 Carles Marti
                           'positive number')
601 eef995b8 Carles Marti
    coll_thrsld_str = dos_inp.get('Screening', 'collision_threshold',
602 eef995b8 Carles Marti
                                  fallback="1.3")
603 eef995b8 Carles Marti
    if coll_thrsld_str.lower() in turn_false_answers:
604 eef995b8 Carles Marti
        return False
605 eef995b8 Carles Marti
    coll_thrsld = try_command(float, [(ValueError, err_msg)], coll_thrsld_str)
606 8887f41d Carles
607 8887f41d Carles
    if coll_thrsld <= 0:
608 8887f41d Carles
        logger.error(err_msg)
609 8887f41d Carles
        raise ValueError(err_msg)
610 8887f41d Carles
611 8887f41d Carles
    return coll_thrsld
612 8887f41d Carles
613 8887f41d Carles
614 f98ba5b0 Carles Marti
def get_min_coll_height(norm_vect):
615 5fb01677 Carles Marti
    err_msg = num_error % ('min_coll_height', 'decimal number')
616 5fb01677 Carles Marti
    min_coll_height = dos_inp.get('Screening', 'min_coll_height',
617 5fb01677 Carles Marti
                                  fallback="False")
618 5fb01677 Carles Marti
    if min_coll_height.lower() in turn_false_answers:
619 f98ba5b0 Carles Marti
        return False
620 f98ba5b0 Carles Marti
    min_coll_height = try_command(float, [(ValueError, err_msg)],
621 f98ba5b0 Carles Marti
                                  min_coll_height)
622 f98ba5b0 Carles Marti
    cart_axes = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0],
623 f98ba5b0 Carles Marti
                 [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, -1.0]]
624 f98ba5b0 Carles Marti
    err_msg = "'min_coll_height' option is only implemented for " \
625 f98ba5b0 Carles Marti
              "'surf_norm_vect' to be one of the x, y or z axes. "
626 8279a51d Carles Marti
    if not isinstance(norm_vect, str) or norm_vect != 'auto':
627 d6da8693 Carles Marti
        check_expect_val(norm_vect.tolist(), cart_axes, err_msg)
628 5fb01677 Carles Marti
    return min_coll_height
629 8887f41d Carles
630 8887f41d Carles
631 c25aa299 Carles Marti
def get_H_donor(spec_atoms):
632 c25aa299 Carles Marti
    from ase.data import chemical_symbols
633 8b3d4772 Carles Marti
    err_msg = "The value of 'h_donor' must be either False, a chemical symbol " \
634 c25aa299 Carles Marti
              "or an atom index"
635 c25aa299 Carles Marti
    h_donor_str = dos_inp.get('Screening', 'h_donor', fallback="False")
636 c25aa299 Carles Marti
    h_donor = []
637 c25aa299 Carles Marti
    if h_donor_str.lower() in turn_false_answers:
638 c25aa299 Carles Marti
        return False
639 c25aa299 Carles Marti
    err = False
640 c25aa299 Carles Marti
    for el in h_donor_str.split():
641 c25aa299 Carles Marti
        try:
642 c25aa299 Carles Marti
            h_donor.append(int(el))
643 c25aa299 Carles Marti
        except ValueError:
644 c25aa299 Carles Marti
            if el not in chemical_symbols + [nw_sym for pairs in spec_atoms
645 c25aa299 Carles Marti
                                             for nw_sym in pairs]:
646 c25aa299 Carles Marti
                err = True
647 c25aa299 Carles Marti
            else:
648 c25aa299 Carles Marti
                h_donor.append(el)
649 c25aa299 Carles Marti
        finally:
650 c25aa299 Carles Marti
            if err:
651 c25aa299 Carles Marti
                logger.error(err_msg)
652 c25aa299 Carles Marti
                ValueError(err_msg)
653 c25aa299 Carles Marti
    return h_donor
654 c25aa299 Carles Marti
655 c25aa299 Carles Marti
656 c25aa299 Carles Marti
def get_H_acceptor(spec_atoms):
657 c25aa299 Carles Marti
    from ase.data import chemical_symbols
658 c25aa299 Carles Marti
    err_msg = "The value of 'h_acceptor' must be either 'all', a chemical " \
659 c25aa299 Carles Marti
              "symbol or an atom index"
660 c25aa299 Carles Marti
    h_acceptor_str = dos_inp.get('Screening', 'h_acceptor', fallback="all")
661 c25aa299 Carles Marti
    if h_acceptor_str.lower() == "all":
662 c25aa299 Carles Marti
        return "all"
663 c25aa299 Carles Marti
    h_acceptor = []
664 c25aa299 Carles Marti
    err = False
665 c25aa299 Carles Marti
    for el in h_acceptor_str.split():
666 c25aa299 Carles Marti
        try:
667 c25aa299 Carles Marti
            h_acceptor.append(int(el))
668 c25aa299 Carles Marti
        except ValueError:
669 c25aa299 Carles Marti
            if el not in chemical_symbols + [nw_sym for pairs in spec_atoms
670 c25aa299 Carles Marti
                                             for nw_sym in pairs]:
671 c25aa299 Carles Marti
                err = True
672 c25aa299 Carles Marti
            else:
673 c25aa299 Carles Marti
                h_acceptor.append(el)
674 c25aa299 Carles Marti
        finally:
675 c25aa299 Carles Marti
            if err:
676 c25aa299 Carles Marti
                logger.error(err_msg)
677 c25aa299 Carles Marti
                ValueError(err_msg)
678 c25aa299 Carles Marti
    return h_acceptor
679 a765b11c Carles Marti
680 a765b11c Carles Marti
681 b75bf97d Carles Marti
def get_use_molec_file():
682 b75bf97d Carles Marti
    use_molec_file = dos_inp.get('Screening', 'use_molec_file',
683 b75bf97d Carles Marti
                                 fallback='False')
684 b75bf97d Carles Marti
    if use_molec_file in turn_false_answers:
685 b75bf97d Carles Marti
        return False
686 b75bf97d Carles Marti
    if not os.path.isfile(use_molec_file):
687 b75bf97d Carles Marti
        logger.error(f'File {use_molec_file} not found.')
688 b75bf97d Carles Marti
        raise FileNotFoundError(f'File {use_molec_file} not found')
689 b75bf97d Carles Marti
690 b75bf97d Carles Marti
    return use_molec_file
691 b75bf97d Carles Marti
692 b75bf97d Carles Marti
693 a7128ce1 Carles Marti
# Refinement
694 a7128ce1 Carles Marti
695 a7128ce1 Carles Marti
def get_refine_inp_file():  # TODO if not specified try isol_inp_file.
696 8887f41d Carles
    refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file')
697 8887f41d Carles
    if not os.path.isfile(refine_inp_file):
698 695dcff8 Carles Marti
        logger.error(f'File {refine_inp_file} not found.')
699 8887f41d Carles
        raise FileNotFoundError(f'File {refine_inp_file} not found')
700 8887f41d Carles
701 8887f41d Carles
    return refine_inp_file
702 8887f41d Carles
703 8887f41d Carles
704 8887f41d Carles
def get_energy_cutoff():
705 8887f41d Carles
    err_msg = num_error % ('energy_cutoff', 'positive decimal number')
706 8887f41d Carles
    energy_cutoff = try_command(dos_inp.getfloat,
707 8887f41d Carles
                                [(ValueError, err_msg)],
708 8887f41d Carles
                                'Refinement', 'energy_cutoff', fallback=0.5)
709 8887f41d Carles
    if energy_cutoff < 0:
710 8887f41d Carles
        logger.error(err_msg)
711 8887f41d Carles
        raise ValueError(err_msg)
712 8887f41d Carles
    return energy_cutoff
713 8887f41d Carles
714 8887f41d Carles
715 c25aa299 Carles Marti
# Read input parameters
716 c25aa299 Carles Marti
717 8887f41d Carles
def read_input(in_file):
718 8887f41d Carles
    err = False
719 8887f41d Carles
    try:
720 8887f41d Carles
        dos_inp.read(in_file)
721 8887f41d Carles
    except MissingSectionHeaderError as e:
722 8887f41d Carles
        logger.error('There are options in the input file without a Section '
723 695dcff8 Carles Marti
                     'header.')
724 8887f41d Carles
        err = e
725 8887f41d Carles
    except DuplicateOptionError as e:
726 8887f41d Carles
        logger.error('There is an option in the input file that has been '
727 0bca5abb Carles Marti
                     'specified more than once.')
728 8887f41d Carles
        err = e
729 8887f41d Carles
    except Exception as e:
730 8887f41d Carles
        err = e
731 8887f41d Carles
    else:
732 8887f41d Carles
        err = False
733 8887f41d Carles
    finally:
734 8887f41d Carles
        if isinstance(err, BaseException):
735 8887f41d Carles
            raise err
736 17e72a49 Carles
737 7dd94df7 Carles Marti
    inp_vars = {}
738 8887f41d Carles
739 8887f41d Carles
    # Global
740 8887f41d Carles
    if not dos_inp.has_section('Global'):
741 8887f41d Carles
        logger.error(no_sect_err % 'Global')
742 8887f41d Carles
        raise NoSectionError('Global')
743 8887f41d Carles
744 8887f41d Carles
    # Mandatory options
745 8887f41d Carles
    # Checks whether the mandatory options 'run_type', 'code', etc. are present.
746 821dca42 Carles Marti
    glob_mand_opts = ['run_type', 'batch_q_sys']
747 7fd58762 Carles
    for opt in glob_mand_opts:
748 8887f41d Carles
        if not dos_inp.has_option('Global', opt):
749 8887f41d Carles
            logger.error(no_opt_err % (opt, 'Global'))
750 8887f41d Carles
            raise NoOptionError(opt, 'Global')
751 8887f41d Carles
752 8887f41d Carles
    # Gets which sections are to be carried out
753 8887f41d Carles
    isolated, screening, refinement = get_run_type()
754 7dd94df7 Carles Marti
    inp_vars['isolated'] = isolated
755 7dd94df7 Carles Marti
    inp_vars['screening'] = screening
756 7dd94df7 Carles Marti
    inp_vars['refinement'] = refinement
757 7dd94df7 Carles Marti
    inp_vars['batch_q_sys'] = get_batch_q_sys()
758 8887f41d Carles
759 99afde40 Carles
    # Dependent options:
760 7dd94df7 Carles Marti
    inp_vars['code'] = get_code()
761 7dd94df7 Carles Marti
    if inp_vars['batch_q_sys']:
762 7dd94df7 Carles Marti
        inp_vars['max_jobs'] = get_max_jobs()
763 7dd94df7 Carles Marti
        if inp_vars['batch_q_sys'] != 'local':
764 09c3325a Carles Marti
            if not dos_inp.has_option('Global', 'subm_script'):
765 09c3325a Carles Marti
                logger.error(no_opt_err % ('subm_script', 'Global'))
766 09c3325a Carles Marti
                raise NoOptionError('subm_script', 'Global')
767 7dd94df7 Carles Marti
            inp_vars['subm_script'] = get_subm_script()
768 99afde40 Carles
769 8887f41d Carles
    # Facultative options (Default/Fallback value present)
770 7dd94df7 Carles Marti
    inp_vars['project_name'] = get_project_name()
771 8b3d4772 Carles Marti
    # inp_vars['relaunch_err'] = get_relaunch_err()
772 7dd94df7 Carles Marti
    inp_vars['special_atoms'] = get_special_atoms()
773 8887f41d Carles
774 8887f41d Carles
    # Isolated
775 b1d27be5 Carles
    if isolated:
776 b606c71a Carles
        if not dos_inp.has_section('Isolated'):
777 b606c71a Carles
            logger.error(no_sect_err % 'Isolated')
778 b606c71a Carles
            raise NoSectionError('Isolated')
779 8887f41d Carles
        # Mandatory options
780 8887f41d Carles
        # Checks whether the mandatory options are present.
781 95dc2c8e Carles
        iso_mand_opts = ['isol_inp_file', 'molec_file']
782 8887f41d Carles
        for opt in iso_mand_opts:
783 8887f41d Carles
            if not dos_inp.has_option('Isolated', opt):
784 8887f41d Carles
                logger.error(no_opt_err % (opt, 'Isolated'))
785 8887f41d Carles
                raise NoOptionError(opt, 'Isolated')
786 7dd94df7 Carles Marti
        inp_vars['isol_inp_file'] = get_isol_inp_file()
787 7dd94df7 Carles Marti
        if 'code ' in inp_vars:
788 7dd94df7 Carles Marti
            check_inp_file(inp_vars['isol_inp_file'], inp_vars['code'])
789 7dd94df7 Carles Marti
        inp_vars['molec_file'] = get_molec_file()
790 8887f41d Carles
791 8887f41d Carles
        # Facultative options (Default/Fallback value present)
792 7dd94df7 Carles Marti
        inp_vars['num_conformers'] = get_num_conformers()
793 7dd94df7 Carles Marti
        # inp_vars['num_prom_cand'] = get_num_prom_cand()
794 7dd94df7 Carles Marti
        # inp_vars['iso_rmsd'] = get_iso_rmsd()
795 7dd94df7 Carles Marti
        inp_vars['pre_opt'] = get_pre_opt()
796 8887f41d Carles
797 8887f41d Carles
    # Screening
798 b1d27be5 Carles
    if screening:
799 772b40e5 Carles
        if not dos_inp.has_section('Screening'):
800 9f7bb440 Carles
            logger.error(no_sect_err % 'Screening')
801 772b40e5 Carles
            raise NoSectionError('Screening')
802 8887f41d Carles
        # Mandatory options:
803 8887f41d Carles
        # Checks whether the mandatory options are present.
804 a765b11c Carles Marti
        screen_mand_opts = ['screen_inp_file', 'surf_file', 'sites',
805 7dd94df7 Carles Marti
                            'molec_ctrs']
806 8887f41d Carles
        for opt in screen_mand_opts:
807 772b40e5 Carles
            if not dos_inp.has_option('Screening', opt):
808 9f7bb440 Carles
                logger.error(no_opt_err % (opt, 'Screening'))
809 b1d27be5 Carles
                raise NoOptionError(opt, 'Screening')
810 7dd94df7 Carles Marti
        inp_vars['screen_inp_file'] = get_screen_inp_file()
811 7dd94df7 Carles Marti
        inp_vars['surf_file'] = get_surf_file()
812 7dd94df7 Carles Marti
        inp_vars['sites'] = get_sites()
813 7dd94df7 Carles Marti
        inp_vars['molec_ctrs'] = get_molec_ctrs()
814 8887f41d Carles
815 8887f41d Carles
        # Facultative options (Default value present)
816 7dd94df7 Carles Marti
        inp_vars['select_magns'] = get_select_magns()
817 7dd94df7 Carles Marti
        inp_vars['confs_per_magn'] = get_confs_per_magn()
818 7dd94df7 Carles Marti
        inp_vars['surf_norm_vect'] = get_surf_norm_vect()
819 7dd94df7 Carles Marti
        inp_vars['set_angles'] = get_set_angles()
820 7dd94df7 Carles Marti
        inp_vars['sample_points_per_angle'] = get_pts_per_angle()
821 c25aa299 Carles Marti
        inp_vars['pbc_cell'] = get_pbc_cell()
822 7dd94df7 Carles Marti
        inp_vars['collision_threshold'] = get_coll_thrsld()
823 f98ba5b0 Carles Marti
        inp_vars['min_coll_height'] = get_min_coll_height(
824 f98ba5b0 Carles Marti
            inp_vars['surf_norm_vect'])
825 8b3d4772 Carles Marti
        if inp_vars['min_coll_height'] is False \
826 8b3d4772 Carles Marti
                and inp_vars['collision_threshold'] is False:
827 8b3d4772 Carles Marti
            logger.warning("Collisions are deactivated: Overlapping of "
828 8b3d4772 Carles Marti
                           "adsorbate and surface is possible")
829 b75bf97d Carles Marti
        inp_vars['h_donor'] = get_H_donor(inp_vars['special_atoms'])
830 b75bf97d Carles Marti
        inp_vars['max_structures'] = get_max_structures()
831 b75bf97d Carles Marti
        inp_vars['use_molec_file'] = get_use_molec_file()
832 8887f41d Carles
833 8b3d4772 Carles Marti
        # Options depending on the value of others
834 7dd94df7 Carles Marti
        if inp_vars['set_angles'] == "chemcat":
835 a98d4172 Carles Marti
            chemcat_opts = ['molec_ctrs2', 'molec_ctrs3', 'surf_ctrs2',
836 a98d4172 Carles Marti
                            'max_helic_angle']
837 7dd94df7 Carles Marti
            for opt in chemcat_opts:
838 7dd94df7 Carles Marti
                if not dos_inp.has_option('Screening', opt):
839 7dd94df7 Carles Marti
                    logger.error(no_opt_err % (opt, 'Screening'))
840 7dd94df7 Carles Marti
                    raise NoOptionError(opt, 'Screening')
841 a98d4172 Carles Marti
            inp_vars['max_helic_angle'] = get_max_helic_angle()
842 7dd94df7 Carles Marti
            inp_vars['molec_ctrs2'] = get_molec_ctrs2()
843 7dd94df7 Carles Marti
            inp_vars['molec_ctrs3'] = get_molec_ctrs3()
844 7dd94df7 Carles Marti
            inp_vars['surf_ctrs2'] = get_surf_ctrs2()
845 7dd94df7 Carles Marti
            if len(inp_vars["molec_ctrs2"]) != len(inp_vars['molec_ctrs']) \
846 7dd94df7 Carles Marti
                    or len(inp_vars["molec_ctrs3"]) != \
847 7dd94df7 Carles Marti
                    len(inp_vars['molec_ctrs']) \
848 7dd94df7 Carles Marti
                    or len(inp_vars['surf_ctrs2']) != len(inp_vars['sites']):
849 c25aa299 Carles Marti
                err = "'molec_ctrs' 'molec_ctrs2' and 'molec_ctrs2' must have " \
850 c25aa299 Carles Marti
                      "the same number of indices "
851 7dd94df7 Carles Marti
                logger.error(err)
852 7dd94df7 Carles Marti
                raise ValueError(err)
853 7dd94df7 Carles Marti
854 c25aa299 Carles Marti
        if inp_vars['h_donor'] is False:
855 c25aa299 Carles Marti
            inp_vars['h_acceptor'] = False
856 c25aa299 Carles Marti
        else:
857 c25aa299 Carles Marti
            inp_vars['h_acceptor'] = get_H_acceptor(inp_vars['special_atoms'])
858 c25aa299 Carles Marti
859 8887f41d Carles
    # Refinement
860 b1d27be5 Carles
    if refinement:
861 8887f41d Carles
        if not dos_inp.has_section('Refinement'):
862 8887f41d Carles
            logger.error(no_sect_err % 'Refinement')
863 8887f41d Carles
            raise NoSectionError('Refinement')
864 8887f41d Carles
        # Mandatory options
865 8887f41d Carles
        # Checks whether the mandatory options are present.
866 8887f41d Carles
        ref_mand_opts = ['refine_inp_file']
867 8887f41d Carles
        for opt in ref_mand_opts:
868 8887f41d Carles
            if not dos_inp.has_option('Refinement', opt):
869 8887f41d Carles
                logger.error(no_opt_err % (opt, 'Refinement'))
870 8887f41d Carles
                raise NoOptionError(opt, 'Refinement')
871 7dd94df7 Carles Marti
        inp_vars['refine_inp_file'] = get_refine_inp_file()
872 8887f41d Carles
873 8887f41d Carles
        # Facultative options (Default value present)
874 7dd94df7 Carles Marti
        inp_vars['energy_cutoff'] = get_energy_cutoff()
875 b1d27be5 Carles
        # end energy_cutoff
876 9f7bb440 Carles
877 a5cc42ff Carles Marti
    return_vars_str = "\n\t".join([str(key) + ": " + str(value)
878 7dd94df7 Carles Marti
                                   for key, value in inp_vars.items()])
879 d8a6314e Carles
    logger.info(
880 62a87644 Carles Marti
        f'Correctly read {in_file} parameters: \n\n\t{return_vars_str}\n')
881 d8a6314e Carles
882 7dd94df7 Carles Marti
    return inp_vars
883 8887f41d Carles
884 8887f41d Carles
885 8887f41d Carles
if __name__ == "__main__":
886 8887f41d Carles
    import sys
887 8887f41d Carles
888 8887f41d Carles
    print(read_input(sys.argv[1]))