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

dockonsurf / modules / dos_input.py @ 8279a51d

Historique | Voir | Annoter | Télécharger (32,7 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 a7128ce1 Carles Marti
# Refinement
682 a7128ce1 Carles Marti
683 a7128ce1 Carles Marti
def get_refine_inp_file():  # TODO if not specified try isol_inp_file.
684 8887f41d Carles
    refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file')
685 8887f41d Carles
    if not os.path.isfile(refine_inp_file):
686 695dcff8 Carles Marti
        logger.error(f'File {refine_inp_file} not found.')
687 8887f41d Carles
        raise FileNotFoundError(f'File {refine_inp_file} not found')
688 8887f41d Carles
689 8887f41d Carles
    return refine_inp_file
690 8887f41d Carles
691 8887f41d Carles
692 8887f41d Carles
def get_energy_cutoff():
693 8887f41d Carles
    err_msg = num_error % ('energy_cutoff', 'positive decimal number')
694 8887f41d Carles
    energy_cutoff = try_command(dos_inp.getfloat,
695 8887f41d Carles
                                [(ValueError, err_msg)],
696 8887f41d Carles
                                'Refinement', 'energy_cutoff', fallback=0.5)
697 8887f41d Carles
    if energy_cutoff < 0:
698 8887f41d Carles
        logger.error(err_msg)
699 8887f41d Carles
        raise ValueError(err_msg)
700 8887f41d Carles
    return energy_cutoff
701 8887f41d Carles
702 8887f41d Carles
703 c25aa299 Carles Marti
# Read input parameters
704 c25aa299 Carles Marti
705 8887f41d Carles
def read_input(in_file):
706 8887f41d Carles
    err = False
707 8887f41d Carles
    try:
708 8887f41d Carles
        dos_inp.read(in_file)
709 8887f41d Carles
    except MissingSectionHeaderError as e:
710 8887f41d Carles
        logger.error('There are options in the input file without a Section '
711 695dcff8 Carles Marti
                     'header.')
712 8887f41d Carles
        err = e
713 8887f41d Carles
    except DuplicateOptionError as e:
714 8887f41d Carles
        logger.error('There is an option in the input file that has been '
715 0bca5abb Carles Marti
                     'specified more than once.')
716 8887f41d Carles
        err = e
717 8887f41d Carles
    except Exception as e:
718 8887f41d Carles
        err = e
719 8887f41d Carles
    else:
720 8887f41d Carles
        err = False
721 8887f41d Carles
    finally:
722 8887f41d Carles
        if isinstance(err, BaseException):
723 8887f41d Carles
            raise err
724 17e72a49 Carles
725 7dd94df7 Carles Marti
    inp_vars = {}
726 8887f41d Carles
727 8887f41d Carles
    # Global
728 8887f41d Carles
    if not dos_inp.has_section('Global'):
729 8887f41d Carles
        logger.error(no_sect_err % 'Global')
730 8887f41d Carles
        raise NoSectionError('Global')
731 8887f41d Carles
732 8887f41d Carles
    # Mandatory options
733 8887f41d Carles
    # Checks whether the mandatory options 'run_type', 'code', etc. are present.
734 821dca42 Carles Marti
    glob_mand_opts = ['run_type', 'batch_q_sys']
735 7fd58762 Carles
    for opt in glob_mand_opts:
736 8887f41d Carles
        if not dos_inp.has_option('Global', opt):
737 8887f41d Carles
            logger.error(no_opt_err % (opt, 'Global'))
738 8887f41d Carles
            raise NoOptionError(opt, 'Global')
739 8887f41d Carles
740 8887f41d Carles
    # Gets which sections are to be carried out
741 8887f41d Carles
    isolated, screening, refinement = get_run_type()
742 7dd94df7 Carles Marti
    inp_vars['isolated'] = isolated
743 7dd94df7 Carles Marti
    inp_vars['screening'] = screening
744 7dd94df7 Carles Marti
    inp_vars['refinement'] = refinement
745 7dd94df7 Carles Marti
    inp_vars['batch_q_sys'] = get_batch_q_sys()
746 8887f41d Carles
747 99afde40 Carles
    # Dependent options:
748 7dd94df7 Carles Marti
    inp_vars['code'] = get_code()
749 7dd94df7 Carles Marti
    if inp_vars['batch_q_sys']:
750 7dd94df7 Carles Marti
        inp_vars['max_jobs'] = get_max_jobs()
751 7dd94df7 Carles Marti
        if inp_vars['batch_q_sys'] != 'local':
752 09c3325a Carles Marti
            if not dos_inp.has_option('Global', 'subm_script'):
753 09c3325a Carles Marti
                logger.error(no_opt_err % ('subm_script', 'Global'))
754 09c3325a Carles Marti
                raise NoOptionError('subm_script', 'Global')
755 7dd94df7 Carles Marti
            inp_vars['subm_script'] = get_subm_script()
756 99afde40 Carles
757 8887f41d Carles
    # Facultative options (Default/Fallback value present)
758 7dd94df7 Carles Marti
    inp_vars['project_name'] = get_project_name()
759 8b3d4772 Carles Marti
    # inp_vars['relaunch_err'] = get_relaunch_err()
760 7dd94df7 Carles Marti
    inp_vars['special_atoms'] = get_special_atoms()
761 8887f41d Carles
762 8887f41d Carles
    # Isolated
763 b1d27be5 Carles
    if isolated:
764 b606c71a Carles
        if not dos_inp.has_section('Isolated'):
765 b606c71a Carles
            logger.error(no_sect_err % 'Isolated')
766 b606c71a Carles
            raise NoSectionError('Isolated')
767 8887f41d Carles
        # Mandatory options
768 8887f41d Carles
        # Checks whether the mandatory options are present.
769 95dc2c8e Carles
        iso_mand_opts = ['isol_inp_file', 'molec_file']
770 8887f41d Carles
        for opt in iso_mand_opts:
771 8887f41d Carles
            if not dos_inp.has_option('Isolated', opt):
772 8887f41d Carles
                logger.error(no_opt_err % (opt, 'Isolated'))
773 8887f41d Carles
                raise NoOptionError(opt, 'Isolated')
774 7dd94df7 Carles Marti
        inp_vars['isol_inp_file'] = get_isol_inp_file()
775 7dd94df7 Carles Marti
        if 'code ' in inp_vars:
776 7dd94df7 Carles Marti
            check_inp_file(inp_vars['isol_inp_file'], inp_vars['code'])
777 7dd94df7 Carles Marti
        inp_vars['molec_file'] = get_molec_file()
778 8887f41d Carles
779 8887f41d Carles
        # Facultative options (Default/Fallback value present)
780 7dd94df7 Carles Marti
        inp_vars['num_conformers'] = get_num_conformers()
781 7dd94df7 Carles Marti
        # inp_vars['num_prom_cand'] = get_num_prom_cand()
782 7dd94df7 Carles Marti
        # inp_vars['iso_rmsd'] = get_iso_rmsd()
783 7dd94df7 Carles Marti
        inp_vars['pre_opt'] = get_pre_opt()
784 8887f41d Carles
785 8887f41d Carles
    # Screening
786 b1d27be5 Carles
    if screening:
787 772b40e5 Carles
        if not dos_inp.has_section('Screening'):
788 9f7bb440 Carles
            logger.error(no_sect_err % 'Screening')
789 772b40e5 Carles
            raise NoSectionError('Screening')
790 8887f41d Carles
        # Mandatory options:
791 8887f41d Carles
        # Checks whether the mandatory options are present.
792 a765b11c Carles Marti
        screen_mand_opts = ['screen_inp_file', 'surf_file', 'sites',
793 7dd94df7 Carles Marti
                            'molec_ctrs']
794 8887f41d Carles
        for opt in screen_mand_opts:
795 772b40e5 Carles
            if not dos_inp.has_option('Screening', opt):
796 9f7bb440 Carles
                logger.error(no_opt_err % (opt, 'Screening'))
797 b1d27be5 Carles
                raise NoOptionError(opt, 'Screening')
798 7dd94df7 Carles Marti
        inp_vars['screen_inp_file'] = get_screen_inp_file()
799 7dd94df7 Carles Marti
        inp_vars['surf_file'] = get_surf_file()
800 7dd94df7 Carles Marti
        inp_vars['sites'] = get_sites()
801 7dd94df7 Carles Marti
        inp_vars['molec_ctrs'] = get_molec_ctrs()
802 8887f41d Carles
803 8887f41d Carles
        # Facultative options (Default value present)
804 7dd94df7 Carles Marti
        inp_vars['select_magns'] = get_select_magns()
805 7dd94df7 Carles Marti
        inp_vars['confs_per_magn'] = get_confs_per_magn()
806 7dd94df7 Carles Marti
        inp_vars['surf_norm_vect'] = get_surf_norm_vect()
807 7dd94df7 Carles Marti
        inp_vars['set_angles'] = get_set_angles()
808 7dd94df7 Carles Marti
        inp_vars['sample_points_per_angle'] = get_pts_per_angle()
809 c25aa299 Carles Marti
        inp_vars['pbc_cell'] = get_pbc_cell()
810 7dd94df7 Carles Marti
        inp_vars['collision_threshold'] = get_coll_thrsld()
811 f98ba5b0 Carles Marti
        inp_vars['min_coll_height'] = get_min_coll_height(
812 f98ba5b0 Carles Marti
            inp_vars['surf_norm_vect'])
813 c25aa299 Carles Marti
        inp_vars['h_donor'] = get_H_donor(inp_vars['special_atoms'])
814 c25aa299 Carles Marti
        inp_vars['max_structures'] = get_max_structures()
815 8b3d4772 Carles Marti
        if inp_vars['min_coll_height'] is False \
816 8b3d4772 Carles Marti
                and inp_vars['collision_threshold'] is False:
817 8b3d4772 Carles Marti
            logger.warning("Collisions are deactivated: Overlapping of "
818 8b3d4772 Carles Marti
                           "adsorbate and surface is possible")
819 8887f41d Carles
820 8b3d4772 Carles Marti
        # Options depending on the value of others
821 7dd94df7 Carles Marti
        if inp_vars['set_angles'] == "chemcat":
822 a98d4172 Carles Marti
            chemcat_opts = ['molec_ctrs2', 'molec_ctrs3', 'surf_ctrs2',
823 a98d4172 Carles Marti
                            'max_helic_angle']
824 7dd94df7 Carles Marti
            for opt in chemcat_opts:
825 7dd94df7 Carles Marti
                if not dos_inp.has_option('Screening', opt):
826 7dd94df7 Carles Marti
                    logger.error(no_opt_err % (opt, 'Screening'))
827 7dd94df7 Carles Marti
                    raise NoOptionError(opt, 'Screening')
828 a98d4172 Carles Marti
            inp_vars['max_helic_angle'] = get_max_helic_angle()
829 7dd94df7 Carles Marti
            inp_vars['molec_ctrs2'] = get_molec_ctrs2()
830 7dd94df7 Carles Marti
            inp_vars['molec_ctrs3'] = get_molec_ctrs3()
831 7dd94df7 Carles Marti
            inp_vars['surf_ctrs2'] = get_surf_ctrs2()
832 7dd94df7 Carles Marti
            if len(inp_vars["molec_ctrs2"]) != len(inp_vars['molec_ctrs']) \
833 7dd94df7 Carles Marti
                    or len(inp_vars["molec_ctrs3"]) != \
834 7dd94df7 Carles Marti
                    len(inp_vars['molec_ctrs']) \
835 7dd94df7 Carles Marti
                    or len(inp_vars['surf_ctrs2']) != len(inp_vars['sites']):
836 c25aa299 Carles Marti
                err = "'molec_ctrs' 'molec_ctrs2' and 'molec_ctrs2' must have " \
837 c25aa299 Carles Marti
                      "the same number of indices "
838 7dd94df7 Carles Marti
                logger.error(err)
839 7dd94df7 Carles Marti
                raise ValueError(err)
840 7dd94df7 Carles Marti
841 c25aa299 Carles Marti
        if inp_vars['h_donor'] is False:
842 c25aa299 Carles Marti
            inp_vars['h_acceptor'] = False
843 c25aa299 Carles Marti
        else:
844 c25aa299 Carles Marti
            inp_vars['h_acceptor'] = get_H_acceptor(inp_vars['special_atoms'])
845 c25aa299 Carles Marti
846 8887f41d Carles
    # Refinement
847 b1d27be5 Carles
    if refinement:
848 8887f41d Carles
        if not dos_inp.has_section('Refinement'):
849 8887f41d Carles
            logger.error(no_sect_err % 'Refinement')
850 8887f41d Carles
            raise NoSectionError('Refinement')
851 8887f41d Carles
        # Mandatory options
852 8887f41d Carles
        # Checks whether the mandatory options are present.
853 8887f41d Carles
        ref_mand_opts = ['refine_inp_file']
854 8887f41d Carles
        for opt in ref_mand_opts:
855 8887f41d Carles
            if not dos_inp.has_option('Refinement', opt):
856 8887f41d Carles
                logger.error(no_opt_err % (opt, 'Refinement'))
857 8887f41d Carles
                raise NoOptionError(opt, 'Refinement')
858 7dd94df7 Carles Marti
        inp_vars['refine_inp_file'] = get_refine_inp_file()
859 8887f41d Carles
860 8887f41d Carles
        # Facultative options (Default value present)
861 7dd94df7 Carles Marti
        inp_vars['energy_cutoff'] = get_energy_cutoff()
862 b1d27be5 Carles
        # end energy_cutoff
863 9f7bb440 Carles
864 a5cc42ff Carles Marti
    return_vars_str = "\n\t".join([str(key) + ": " + str(value)
865 7dd94df7 Carles Marti
                                   for key, value in inp_vars.items()])
866 d8a6314e Carles
    logger.info(
867 62a87644 Carles Marti
        f'Correctly read {in_file} parameters: \n\n\t{return_vars_str}\n')
868 d8a6314e Carles
869 7dd94df7 Carles Marti
    return inp_vars
870 8887f41d Carles
871 8887f41d Carles
872 8887f41d Carles
if __name__ == "__main__":
873 8887f41d Carles
    import sys
874 8887f41d Carles
875 8887f41d Carles
    print(read_input(sys.argv[1]))