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

dockonsurf / modules / dos_input.py @ 9cd032cf

Historique | Voir | Annoter | Télécharger (34 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 9cd032cf Carles Marti
    dos_inp.BOOLEAN_STATES[answer] = val  # TODO Check value 0
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 9cd032cf Carles Marti
turn_true_answers = [answer for answer in dos_inp.BOOLEAN_STATES
65 9cd032cf Carles Marti
                     if dos_inp.BOOLEAN_STATES[answer]]
66 8887f41d Carles
67 8887f41d Carles
no_sect_err = "Section '%s' not found on input file"
68 8887f41d Carles
no_opt_err = "Option '%s' not found on section '%s'"
69 8887f41d Carles
num_error = "'%s' value must be a %s"
70 8887f41d Carles
71 4533134f Carles Marti
72 4533134f Carles Marti
def str2lst(cmplx_str, func=int):  # TODO: enable deeper level of nested lists
73 a7128ce1 Carles Marti
    # TODO Treat all-enclosing parenthesis as a list instead of list of lists.
74 b77be9ad Carles
    """Converts a string of integers, and groups of them, to a list.
75 b77be9ad Carles

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

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

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

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