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

dockonsurf / modules / dos_input.py @ 8af49f6d

Historique | Voir | Annoter | Télécharger (25,56 ko)

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

3
Functions
4
try_command:Tries to run a command and logs its exceptions (expected and not).
5
str2lst: Converts a string of integers, and groups of them, to a list of lists.
6
check_expect_val: Checks whether the value of an option has an adequate value.
7
read_input: Sets up the calculation by reading the parameters from input file.
8
get_run_type: Gets 'run_type' value and checks that its value is acceptable.
9
get_code: Gets 'code' value and checks that its value is acceptable.
10
get_batch_q_sys: Gets 'batch_q_sys' value and checks that its value is
11
acceptable.
12
get_relaunch_err: Gets 'relaunch_err' value and checks that its value is
13
acceptable.
14
get_max_qw: Gets 'max_qw' value and checks that its value is acceptable.
15
get_special_atoms: Gets 'special_atoms' value and checks that its value is
16
acceptable.
17
get_isol_inp_file: Gets 'isol_inp_file' value and checks that its value is
18
acceptable.
19
get_cluster_magns: Gets 'cluster_magns' value and checks that its value is
20
acceptable.
21
get_num_conformers: Gets 'num_conformers' value and checks that its value is
22
acceptable.
23
get_num_prom_cand: Gets 'num_prom_cand' value and checks that its value is
24
acceptable.
25
get_iso_rmsd: Gets 'iso_rmsd' value and checks that its value is acceptable.
26
get_min_confs: Gets 'min_confs' value and checks that its value is acceptable.
27
get_screen_inp_file: Gets 'screen_inp_file' value and checks that its value is
28
acceptable.
29
get_sites: Gets 'sites' value and checks that its value is acceptable.
30
get_molec_ads_ctrs: Gets 'molec_ads_ctrs' value and checks that its value is
31
acceptable.
32
get_try_disso: Gets 'try_disso' value and checks that its value is acceptable.
33
get_pts_per_angle: Gets 'pts_per_angle' value and checks that its value is
34
acceptable.
35
get_coll_thrsld: Gets 'coll_thrsld' value and checks that its value is
36
acceptable.
37
get_screen_rmsd: Gets 'screen_rmsd' value and checks that its value is
38
acceptable.
39
get_coll_bottom_z: Gets 'coll_bottom_z' value and checks that its value is
40
acceptable.
41
get_refine_inp_file: Gets 'refine_inp_file' value and checks that its value is
42
acceptable.
43
get_energy_cutoff: Gets 'energy_cutoff' value and checks that its value is
44
acceptable.
45
"""
46
import os.path
47
import logging
48
from configparser import ConfigParser, NoSectionError, NoOptionError, \
49
    MissingSectionHeaderError, DuplicateOptionError
50
from modules.utilities import try_command
51

    
52
logger = logging.getLogger('DockOnSurf')
53

    
54
dos_inp = ConfigParser(inline_comment_prefixes='#',
55
                       empty_lines_in_values=False)
56

    
57
new_answers = {'n': False, 'none': False, 'nay': False,
58
               'y': True, '': True, 'aye': True, 'sure': True}
59
for answer, val in new_answers.items():
60
    dos_inp.BOOLEAN_STATES[answer] = val
61
turn_false_answers = [answer for answer in dos_inp.BOOLEAN_STATES
62
                      if dos_inp.BOOLEAN_STATES[answer] is False]
63

    
64
no_sect_err = "Section '%s' not found on input file"
65
no_opt_err = "Option '%s' not found on section '%s'"
66
num_error = "'%s' value must be a %s"
67

    
68

    
69
def str2lst(cmplx_str, func=int):  # TODO: enable deeper level of nested lists
70
    """Converts a string of integers, and groups of them, to a list.
71

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

80
    @return list, list of integers (or floats), or list of integers (or floats)
81
    in the case they were grouped. First, the singlets are placed, and then the
82
    groups in input order.
83

84
    eg. '128,(135 138;141] 87 {45, 68}' -> [128, 87, [135, 138, 141], [45, 68]]
85
    """
86

    
87
    # Checks
88
    error_msg = "Function argument should be a str,sequence of integer " \
89
                "numbers separated by ',' ';' or ' '." \
90
                "\nThey can be grouped in parentheses-like enclosers: '()', " \
91
                "'[]' or {}. Nested groups are not allowed. \n" \
92
                "eg. 128,(135 138;141) 87 {45, 68}"
93
    cmplx_str = try_command(cmplx_str.replace, [(AttributeError, error_msg)],
94
                            ',', ' ')
95

    
96
    cmplx_str = cmplx_str.replace(';', ' ').replace('[', '(').replace(
97
        ']', ')').replace('{', '(').replace('}', ')')
98

    
99
    try_command(list, [(ValueError, error_msg)], map(func, cmplx_str.replace(
100
        ')', '').replace('(', '').split()))
101

    
102
    deepness = 0
103
    for el in cmplx_str.split():
104
        if '(' in el:
105
            deepness += 1
106
        if ')' in el:
107
            deepness += -1
108
        if deepness > 1 or deepness < 0:
109
            logger.error(error_msg)
110
            raise ValueError(error_msg)
111

    
112
    init_list = cmplx_str.split()
113
    start_group = []
114
    end_group = []
115
    for i, element in enumerate(init_list):
116
        if '(' in element:
117
            start_group.append(i)
118
            init_list[i] = element.replace('(', '')
119
        if ')' in element:
120
            end_group.append(i)
121
            init_list[i] = element.replace(')', '')
122

    
123
    init_list = list(map(func, init_list))
124

    
125
    new_list = []
126
    for start_el, end_el in zip(start_group, end_group):
127
        new_list.append(init_list[start_el:end_el + 1])
128

    
129
    for v in new_list:
130
        for el in v:
131
            init_list.remove(el)
132
    return init_list + new_list
133

    
134

    
135
def check_expect_val(value, expect_vals):
136
    """Checks whether an option lies within its expected values.
137

138
    Keyword arguments:
139
    @param value: The variable to check if its value lies within the expected
140
    ones
141
    @param expect_vals: list, list of values allowed for the present option.
142
    @raise ValueError: if the value is not among the expected ones.
143
    @return True if the value is among the expected ones.
144
    """
145
    adeq_val_err = "'%s' is not an adequate value.\n" \
146
                   "Adequate values: %s"
147
    if not any([exp_val == value for exp_val in expect_vals]):
148
        logger.error(adeq_val_err % (value, expect_vals))
149
        raise ValueError(adeq_val_err % (value, expect_vals))
150

    
151
    return True
152

    
153

    
154
def check_inp_file(inp_file, code):
155
    if code == 'cp2k':
156
        from pycp2k import CP2K
157
        cp2k = CP2K()
158
        try_command(cp2k.parse,
159
                    [(UnboundLocalError, "Invalid CP2K input file")], inp_file)
160

    
161

    
162
def get_run_type():
163
    isolated, screening, refinement = (False, False, False)
164
    run_type_vals = ['isolated', 'screening', 'refinement', 'adsorption',
165
                     'full']
166
    check_expect_val(dos_inp.get('Global', 'run_type').lower(), run_type_vals)
167

    
168
    run_type = dos_inp.get('Global', 'run_type').lower()
169
    if 'isolated' in run_type:
170
        isolated = True
171
    if 'screening' in run_type:
172
        screening = True
173
    if 'refinement' in run_type:
174
        refinement = True
175
    if 'adsorption' in run_type:
176
        screening, refinement = (True, True)
177
    if 'full' in run_type:
178
        isolated, screening, refinement = (True, True, True)
179

    
180
    return isolated, screening, refinement
181

    
182

    
183
def get_code():
184
    code_vals = ['cp2k']
185
    check_expect_val(dos_inp.get('Global', 'code').lower(), code_vals)
186
    code = dos_inp.get('Global', 'code').lower()
187
    return code
188

    
189

    
190
def get_batch_q_sys():
191
    batch_q_sys_vals = ['sge', 'lsf', 'local'] + turn_false_answers
192
    check_expect_val(dos_inp.get('Global', 'batch_q_sys').lower(),
193
                     batch_q_sys_vals)
194
    batch_q_sys = dos_inp.get('Global', 'batch_q_sys').lower()
195
    if batch_q_sys.lower() in turn_false_answers:
196
        return False
197
    else:
198
        return batch_q_sys
199

    
200

    
201
def get_subm_script():
202
    subm_script = dos_inp.get('Global', 'subm_script', fallback=False)
203
    if subm_script and not os.path.isfile(subm_script):
204
        logger.error(f'File {subm_script} not found')
205
        raise FileNotFoundError(f'File {subm_script} not found')
206
    return subm_script
207

    
208

    
209
def get_project_name():
210
    project_name = dos_inp.get('Global', 'project_name', fallback='')
211
    return project_name
212

    
213

    
214
def get_relaunch_err():
215
    relaunch_err_vals = ['geo_not_conv', 'false']
216
    relaunch_err = dos_inp.get('Global', 'relaunch_err',
217
                               fallback="False")
218
    if relaunch_err.lower() in turn_false_answers:
219
        return False
220
    else:
221
        check_expect_val(relaunch_err.lower(), relaunch_err_vals)
222
    return relaunch_err
223

    
224

    
225
def get_max_qw():
226
    err_msg = num_error % ('max_qw', 'positive integer')
227
    max_qw = try_command(dos_inp.getint, [(ValueError, err_msg)],
228
                         'Global', 'max_qw', fallback=3)
229

    
230
    if max_qw < 1:
231
        logger.error(num_error % ('max_qw', 'positive integer'))
232
        raise ValueError(num_error % ('max_qw', 'positive integer'))
233
    return max_qw
234

    
235

    
236
def get_special_atoms():
237
    from ase.data import chemical_symbols
238

    
239
    spec_at_err = '\'special_atoms\' does not have an adequate format.\n' \
240
                  'Adequate format: (Fe1 Fe) (O1 O)'
241
    special_atoms = dos_inp.get('Global', 'special_atoms', fallback="False")
242
    if special_atoms.lower() in turn_false_answers:
243
        special_atoms = False
244
    else:
245
        # Converts the string into a list of tuples
246
        lst_tple = [tuple(pair.replace("(", "").split()) for pair in
247
                    special_atoms.split(")")[:-1]]
248
        if len(lst_tple) == 0:
249
            logger.error(spec_at_err)
250
            raise ValueError(spec_at_err)
251
        for i, tup in enumerate(lst_tple):
252
            if type(tup) is not tuple or len(tup) != 2:
253
                logger.error(spec_at_err)
254
                raise ValueError(spec_at_err)
255
            if tup[1].capitalize() not in chemical_symbols:
256
                elem_err = "The second element of the couple should be an " \
257
                           "actual element of the periodic table"
258
                logger.error(elem_err)
259
                raise ValueError(elem_err)
260
            if tup[0].capitalize() in chemical_symbols:
261
                elem_err = "The first element of the couple is already an " \
262
                           "actual element of the periodic table, "
263
                logger.error(elem_err)
264
                raise ValueError(elem_err)
265
            for j, tup2 in enumerate(lst_tple):
266
                if j <= i:
267
                    continue
268
                if tup2[0] == tup[0]:
269
                    label_err = f'You have specified the label {tup[0]} to ' \
270
                                f'more than one special atom'
271
                    logger.error(label_err)
272
                    raise ValueError(label_err)
273
        special_atoms = lst_tple
274
    return special_atoms
275

    
276

    
277
def get_isol_inp_file():
278
    isol_inp_file = dos_inp.get('Isolated', 'isol_inp_file')
279
    if not os.path.isfile(isol_inp_file):
280
        logger.error(f'File {isol_inp_file} not found')
281
        raise FileNotFoundError(f'File {isol_inp_file} not found')
282
    return isol_inp_file
283

    
284

    
285
def get_molec_file():
286
    molec_file = dos_inp.get('Isolated', 'molec_file')
287
    if not os.path.isfile(molec_file):
288
        logger.error(f'File {molec_file} not found')
289
        raise FileNotFoundError(f'File {molec_file} not found')
290
    return molec_file
291

    
292

    
293
def get_num_conformers():
294
    err_msg = num_error % ('num_conformers', 'positive integer')
295
    num_conformers = try_command(dos_inp.getint, [(ValueError, err_msg)],
296
                                 'Isolated', 'num_conformers', fallback=100)
297
    if num_conformers < 1:
298
        logger.error(err_msg)
299
        raise ValueError(err_msg)
300
    return num_conformers
301

    
302

    
303
def get_num_prom_cand():
304
    err_msg = num_error % ('num_prom_cand', 'positive integer')
305
    num_prom_cand = try_command(dos_inp.getint, [(ValueError, err_msg)],
306
                                'Isolated', 'num_prom_cand', fallback=3)
307
    if num_prom_cand < 1:
308
        logger.error(err_msg)
309
        raise ValueError(err_msg)
310
    return num_prom_cand
311

    
312

    
313
def get_iso_rmsd():
314
    err_msg = num_error % ('iso_rmsd', 'positive decimal number')
315
    iso_rmsd = try_command(dos_inp.getfloat, [(ValueError, err_msg)],
316
                           'Isolated', 'iso_rmsd', fallback=0.05)
317
    if iso_rmsd <= 0.0:
318
        logger.error(err_msg)
319
        raise ValueError(err_msg)
320
    return iso_rmsd
321

    
322

    
323
def get_min_confs():
324
    err_msg = "'min_confs' should be have a boolean value (True or False)"
325
    min_confs = try_command(dos_inp.getboolean,
326
                            [(ValueError, err_msg)],
327
                            'Isolated', 'min_confs', fallback=True)
328
    return min_confs
329

    
330

    
331
def get_screen_inp_file():
332
    screen_inp_file = dos_inp.get('Screening', 'screen_inp_file')
333
    if not os.path.isfile(screen_inp_file):
334
        logger.error(f'File {screen_inp_file} not found')
335
        raise FileNotFoundError(f'File {screen_inp_file} not found')
336
    return screen_inp_file
337

    
338

    
339
def get_sites():
340
    err_msg = 'The value of sites should be a list of atom numbers ' \
341
              '(ie. positive integers) or groups of atom numbers ' \
342
              'grouped by parentheses-like enclosers. \n' \
343
              'eg. 128,(135 138;141) 87 {45, 68}'
344
    # Convert the string into a list of lists
345
    sites = try_command(str2lst,
346
                        [(ValueError, err_msg), (AttributeError, err_msg)],
347
                        dos_inp.get('Screening', 'sites'))
348
    # Check all elements of the list (of lists) are positive integers
349
    for site in sites:
350
        if type(site) is list:
351
            for atom in site:
352
                if atom < 0:
353
                    logger.error(err_msg)
354
                    raise ValueError(err_msg)
355
        elif type(site) is int:
356
            if site < 0:
357
                logger.error(err_msg)
358
                raise ValueError(err_msg)
359
        else:
360
            logger.error(err_msg)
361
            raise ValueError(err_msg)
362

    
363
    return sites
364

    
365

    
366
def get_molec_ads_ctrs():
367
    err_msg = 'The value of molec_ads_ctrs should be a list of atom' \
368
              ' numbers (ie. positive integers) or groups of atom ' \
369
              'numbers enclosed by parentheses-like characters. \n' \
370
              'eg. 128,(135 138;141) 87 {45, 68}'
371
    # Convert the string into a list of lists
372
    molec_ads_ctrs = try_command(str2lst,
373
                                 [(ValueError, err_msg),
374
                                  (AttributeError, err_msg)],
375
                                 dos_inp.get('Screening', 'molec_ads_ctrs'))
376
    # Check all elements of the list (of lists) are positive integers
377
    for ctr in molec_ads_ctrs:
378
        if isinstance(ctr, list):
379
            for atom in ctr:
380
                if atom < 0:
381
                    logger.error(err_msg)
382
                    raise ValueError(err_msg)
383
        elif isinstance(ctr, int):
384
            if ctr < 0:
385
                logger.error(err_msg)
386
                raise ValueError(err_msg)
387
        else:
388
            logger.error(err_msg)
389
            raise ValueError(err_msg)
390

    
391
    return molec_ads_ctrs
392

    
393

    
394
def get_surf_file():
395
    surf_file = dos_inp.get('Screening', 'surf_file')
396
    if not os.path.isfile(surf_file):
397
        logger.error(f'File {surf_file} not found')
398
        raise FileNotFoundError(f'File {surf_file} not found')
399
    return surf_file
400

    
401

    
402
def get_molec_neigh_ctrs():
403
    err_msg = 'The value of molec_neigh_ctrs should be a list of atom ' \
404
              'numbers (ie. positive integers) or groups of atom ' \
405
              'numbers enclosed by parentheses-like characters. \n' \
406
              'eg. 128,(135 138;141) 87 {45, 68}'
407
    # Convert the string into a list of lists
408
    molec_neigh_ctrs = try_command(str2lst, [(ValueError, err_msg),
409
                                             (AttributeError, err_msg)],
410
                                   dos_inp.get('Screening', 'molec_neigh_ctrs'))
411

    
412
    # Check all elements of the list (of lists) are positive integers
413
    for ctr in molec_neigh_ctrs:
414
        if isinstance(ctr, list):
415
            for atom in ctr:
416
                if atom < 0:
417
                    logger.error(err_msg)
418
                    raise ValueError(err_msg)
419
        elif isinstance(ctr, int):
420
            if ctr < 0:
421
                logger.error(err_msg)
422
                raise ValueError(err_msg)
423
        else:
424
            logger.error(err_msg)
425
            raise ValueError(err_msg)
426

    
427
    return molec_neigh_ctrs
428

    
429

    
430
def get_select_magns():
431
    select_magns_vals = ['energy', 'moi']
432
    select_magns_str = dos_inp.get('Screening', 'select_magns',
433
                                    fallback='energy')
434
    select_magns_str.replace(',', ' ').replace(';', ' ')
435
    select_magns = select_magns_str.split(' ')
436
    select_magns = [m.lower() for m in select_magns]
437
    for m in select_magns:
438
        check_expect_val(m, select_magns_vals)
439
    return select_magns
440

    
441

    
442
def get_surf_norm_vect():
443
    import numpy as np
444
    err = "'surf_norm_vect' must be either a 3 component vector or 'x', 'y' " \
445
          "or 'z'"
446
    coords = {'x': [1.0, 0.0, 0.0],
447
              'y': [0.0, 1.0, 0.0],
448
              'z': [0.0, 0.0, 1.0]}
449
    surf_norm_vect_str = dos_inp.get('Screening', 'surf_norm_vect',
450
                                     fallback="0.0 0.0 1.0")
451
    try:
452
        surf_norm_vect = str2lst(surf_norm_vect_str, float)
453
        if len(surf_norm_vect) != 3:
454
            logger.error(err)
455
            raise ValueError(err)
456
    except ValueError:
457
        if len(surf_norm_vect_str) != 1 or surf_norm_vect_str not in coords:
458
            logger.error(err)
459
            raise ValueError(err)
460
        else:
461
            surf_norm_vect = coords[surf_norm_vect_str]
462
    return np.array(surf_norm_vect)
463

    
464

    
465
def get_try_disso():
466
    err_msg = "try_disso should be have a boolean value (True or False)"
467
    try_disso = try_command(dos_inp.getboolean,
468
                            [(ValueError, err_msg)],
469
                            'Screening', 'try_disso', fallback=False)
470
    return try_disso
471

    
472

    
473
def get_ads_algo():
474
    algo_vals = ['euler', 'chemcat']
475
    check_expect_val(dos_inp.get('Screening', 'ads_algo').lower(), algo_vals)
476
    ads_algo = dos_inp.get('Screening', 'ads_algo').lower()
477
    return ads_algo
478

    
479

    
480

    
481
def get_pts_per_angle():
482
    err_msg = num_error % ('sample_points_per_angle', 'positive integer')
483
    pts_per_angle = try_command(dos_inp.getint,
484
                                [(ValueError, err_msg)],
485
                                'Screening', 'sample_points_per_angle',
486
                                fallback=3)
487
    if pts_per_angle <= 0:
488
        logger.error(err_msg)
489
        raise ValueError(err_msg)
490
    return pts_per_angle
491

    
492

    
493
def get_coll_thrsld():
494
    err_msg = num_error % ('collision_threshold',
495
                           'positive decimal number')
496

    
497
    coll_thrsld = try_command(dos_inp.getfloat,
498
                              [(ValueError, err_msg)],
499
                              'Screening', 'collision_threshold', fallback=1.2)
500
    if coll_thrsld <= 0:
501
        logger.error(err_msg)
502
        raise ValueError(err_msg)
503

    
504
    return coll_thrsld
505

    
506

    
507
def get_screen_rmsd():
508
    err_msg = num_error % ('screen_rmsd', 'positive decimal number')
509
    screen_rmsd = try_command(dos_inp.getfloat,
510
                              [(ValueError, err_msg)],
511
                              'Screening', 'screen_rmsd', fallback=0.05)
512
    if screen_rmsd <= 0:
513
        logger.error(err_msg)
514
        raise ValueError(err_msg)
515

    
516
    return screen_rmsd
517

    
518

    
519
def get_coll_bottom():
520
    err_msg = num_error % ('collision_bottom', 'decimal number')
521
    coll_bottom = dos_inp.get('Screening', 'collision_bottom',
522
                              fallback="False")
523
    if coll_bottom.lower() in turn_false_answers:
524
        coll_bottom = False
525
    else:
526
        coll_bottom = try_command(float, [(ValueError, err_msg)], coll_bottom)
527

    
528
    return coll_bottom
529

    
530

    
531
def get_refine_inp_file():
532
    refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file')
533
    if not os.path.isfile(refine_inp_file):
534
        logger.error(f'File {refine_inp_file} not found')
535
        raise FileNotFoundError(f'File {refine_inp_file} not found')
536

    
537
    return refine_inp_file
538

    
539

    
540
def get_energy_cutoff():
541
    err_msg = num_error % ('energy_cutoff', 'positive decimal number')
542
    energy_cutoff = try_command(dos_inp.getfloat,
543
                                [(ValueError, err_msg)],
544
                                'Refinement', 'energy_cutoff', fallback=0.5)
545
    if energy_cutoff < 0:
546
        logger.error(err_msg)
547
        raise ValueError(err_msg)
548
    return energy_cutoff
549

    
550

    
551
def read_input(in_file):
552
    err = False
553
    try:
554
        dos_inp.read(in_file)
555
    except MissingSectionHeaderError as e:
556
        logger.error('There are options in the input file without a Section '
557
                     'header')
558
        err = e
559
    except DuplicateOptionError as e:
560
        logger.error('There is an option in the input file that has been '
561
                     'specified more than once, possibly due to the lack of a '
562
                     'Section header')
563
        err = e
564
    except Exception as e:
565
        err = e
566
    else:
567
        err = False
568
    finally:
569
        if isinstance(err, BaseException):
570
            raise err
571

    
572
    return_vars = {}
573

    
574
    # Global
575
    if not dos_inp.has_section('Global'):
576
        logger.error(no_sect_err % 'Global')
577
        raise NoSectionError('Global')
578

    
579
    # Mandatory options
580
    # Checks whether the mandatory options 'run_type', 'code', etc. are present.
581
    glob_mand_opts = ['run_type', 'batch_q_sys']
582
    for opt in glob_mand_opts:
583
        if not dos_inp.has_option('Global', opt):
584
            logger.error(no_opt_err % (opt, 'Global'))
585
            raise NoOptionError(opt, 'Global')
586

    
587
    # Gets which sections are to be carried out
588
    isolated, screening, refinement = get_run_type()
589
    return_vars['isolated'] = isolated
590
    return_vars['screening'] = screening
591
    return_vars['refinement'] = refinement
592
    return_vars['batch_q_sys'] = get_batch_q_sys()
593

    
594
    # Dependent options:
595
    return_vars['code'] = get_code()
596
    if return_vars['batch_q_sys'] and return_vars['batch_q_sys'] != 'local':
597
        if not dos_inp.has_option('Global', 'subm_script'):
598
            logger.error(no_opt_err % ('subm_script', 'Global'))
599
            raise NoOptionError('subm_script', 'Global')
600
        return_vars['subm_script'] = get_subm_script()
601
        return_vars['max_qw'] = get_max_qw()
602

    
603
    # Facultative options (Default/Fallback value present)
604
    return_vars['project_name'] = get_project_name()
605
    return_vars['relaunch_err'] = get_relaunch_err()
606
    return_vars['special_atoms'] = get_special_atoms()
607

    
608
    # Isolated
609
    if isolated:
610
        if not dos_inp.has_section('Isolated'):
611
            logger.error(no_sect_err % 'Isolated')
612
            raise NoSectionError('Isolated')
613
        # Mandatory options
614
        # Checks whether the mandatory options are present.
615
        iso_mand_opts = ['isol_inp_file', 'molec_file']
616
        for opt in iso_mand_opts:
617
            if not dos_inp.has_option('Isolated', opt):
618
                logger.error(no_opt_err % (opt, 'Isolated'))
619
                raise NoOptionError(opt, 'Isolated')
620
        return_vars['isol_inp_file'] = get_isol_inp_file()
621
        if 'code ' in return_vars:
622
            check_inp_file(return_vars['isol_inp_file'], return_vars['code'])
623
        return_vars['molec_file'] = get_molec_file()
624

    
625
        # Facultative options (Default/Fallback value present)
626
        return_vars['num_conformers'] = get_num_conformers()
627
        # return_vars['num_prom_cand'] = get_num_prom_cand()
628
        # return_vars['iso_rmsd'] = get_iso_rmsd()
629
        return_vars['min_confs'] = get_min_confs()
630

    
631
    # Screening
632
    if screening:
633
        if not dos_inp.has_section('Screening'):
634
            logger.error(no_sect_err % 'Screening')
635
            raise NoSectionError('Screening')
636
        # Mandatory options:
637
        # Checks whether the mandatory options are present.
638
        screen_mand_opts = ['sites', 'molec_ads_ctrs', 'screen_inp_file',
639
                            'surf_file', 'molec_neigh_ctrs']
640
        for opt in screen_mand_opts:
641
            if not dos_inp.has_option('Screening', opt):
642
                logger.error(no_opt_err % (opt, 'Screening'))
643
                raise NoOptionError(opt, 'Screening')
644
        return_vars['screen_inp_file'] = get_screen_inp_file()
645
        return_vars['sites'] = get_sites()
646
        return_vars['molec_ads_ctrs'] = get_molec_ads_ctrs()
647
        return_vars['surf_file'] = get_surf_file()
648
        return_vars['molec_neigh_ctrs'] = get_molec_neigh_ctrs()
649
        if len(return_vars['molec_ads_ctrs']) != \
650
                len(return_vars['molec_neigh_ctrs']):
651
            err = "'molec_ads_ctrs' and 'molec_neigh_ctrs' must have the same" \
652
                  "number of indides"
653
            logger.error(err)
654
            raise ValueError(err)
655

    
656
        # Facultative options (Default value present)
657
        return_vars['select_magns'] = get_select_magns()
658
        return_vars['surf_norm_vect'] = get_surf_norm_vect()
659
        return_vars['try_disso'] = get_try_disso()
660
        return_vars['ads_algo'] = get_ads_algo()
661
        return_vars['sample_points_per_angle'] = get_pts_per_angle()
662
        return_vars['collision_threshold'] = get_coll_thrsld()
663
        # return_vars['screen_rmsd'] = get_screen_rmsd()
664
        return_vars['collision_bottom'] = get_coll_bottom()
665

    
666
    # Refinement
667
    if refinement:
668
        if not dos_inp.has_section('Refinement'):
669
            logger.error(no_sect_err % 'Refinement')
670
            raise NoSectionError('Refinement')
671
        # Mandatory options
672
        # Checks whether the mandatory options are present.
673
        ref_mand_opts = ['refine_inp_file']
674
        for opt in ref_mand_opts:
675
            if not dos_inp.has_option('Refinement', opt):
676
                logger.error(no_opt_err % (opt, 'Refinement'))
677
                raise NoOptionError(opt, 'Refinement')
678
        return_vars['refine_inp_file'] = get_refine_inp_file()
679

    
680
        # Facultative options (Default value present)
681
        return_vars['energy_cutoff'] = get_energy_cutoff()
682
        # end energy_cutoff
683

    
684
    return_vars_str = "\n\t".join([str(key) + ": " + str(value)
685
                                   for key, value in return_vars.items()])
686
    logger.info(
687
        f'Correctly read {in_file} parameters: \n\n\t{return_vars_str}\n')
688

    
689
    return return_vars
690

    
691

    
692
if __name__ == "__main__":
693
    import sys
694

    
695
    print(read_input(sys.argv[1]))