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

dockonsurf / modules / dos_input.py @ 69d17e8b

Historique | Voir | Annoter | Télécharger (22,48 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 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
unexp_error = "An unexpected error occurred"
68

    
69

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

73
    Keyword arguments:
74
    @param cmplx_str: str, string of integers and groups of them enclosed by
75
    parentheses-like characters.
76
    - Group enclosers: '()' '[]' and '{}'.
77
    - Integer separators: ',' ';' and ' '.
78
    - Nested groups are not allowed: '3 ((6 7) 8) 4'.
79

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

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

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

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

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

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

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

    
122
    init_list = list(map(int, init_list))
123

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

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

    
133

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

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

    
150
    return True
151

    
152

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

    
160

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

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

    
179
    return isolated, screening, refinement
180

    
181

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

    
188

    
189
def get_batch_q_sys():
190
    batch_q_sys_vals = ['sge', 'lsf', 'local', 'none']
191
    check_expect_val(dos_inp.get('Global', 'batch_q_sys').lower(),
192
                     batch_q_sys_vals)
193
    batch_q_sys = dos_inp.get('Global', 'batch_q_sys').lower()
194
    return batch_q_sys
195

    
196

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

    
204

    
205
def get_project_name():
206
    project_name = dos_inp.get('Global', 'project_name', fallback='')
207
    return project_name
208

    
209

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

    
220

    
221
def get_max_qw():
222
    err_msg = num_error % ('max_qw', 'positive integer')
223
    max_qw = try_command(dos_inp.getint, [(ValueError, err_msg)],
224
                         'Global', 'max_qw', fallback=3)
225

    
226
    if max_qw < 1:
227
        logger.error(num_error % ('max_qw', 'positive integer'))
228
        raise ValueError(num_error % ('max_qw', 'positive integer'))
229
    return max_qw
230

    
231

    
232
def get_special_atoms():
233
    from ase.data import chemical_symbols
234

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

    
272

    
273
def get_isol_inp_file():
274
    isol_inp_file = dos_inp.get('Isolated', 'isol_inp_file')
275
    if not os.path.isfile(isol_inp_file):
276
        logger.error(f'File {isol_inp_file} not found')
277
        raise FileNotFoundError(f'File {isol_inp_file} not found')
278
    return isol_inp_file
279

    
280

    
281
def get_molec_file():
282
    molec_file = dos_inp.get('Isolated', 'molec_file')
283
    if not os.path.isfile(molec_file):
284
        logger.error(f'File {molec_file} not found')
285
        raise FileNotFoundError(f'File {molec_file} not found')
286
    return molec_file
287

    
288

    
289
def get_cluster_magns():
290
    clust_magns_vals = ['energy', 'moi']
291
    cluster_magns_str = dos_inp.get('Isolated', 'cluster_magns',
292
                                    fallback='energy')
293
    cluster_magns_str.replace(',', ' ').replace(';', ' ')
294
    cluster_magns = cluster_magns_str.split(' ')
295
    cluster_magns = [m.lower() for m in cluster_magns]
296
    for m in cluster_magns:
297
        check_expect_val(m, clust_magns_vals)
298
    return cluster_magns
299

    
300

    
301
def get_num_conformers():
302
    err_msg = num_error % ('num_conformers', 'positive integer')
303
    num_conformers = try_command(dos_inp.getint, [(ValueError, err_msg)],
304
                                 'Isolated', 'num_conformers', fallback=100)
305
    if num_conformers < 1:
306
        logger.error(err_msg)
307
        raise ValueError(err_msg)
308
    return num_conformers
309

    
310

    
311
def get_num_prom_cand():
312
    err_msg = num_error % ('num_prom_cand', 'positive integer')
313
    num_prom_cand = try_command(dos_inp.getint, [(ValueError, err_msg)],
314
                                'Isolated', 'num_prom_cand', fallback=3)
315
    if num_prom_cand < 1:
316
        logger.error(err_msg)
317
        raise ValueError(err_msg)
318
    return num_prom_cand
319

    
320

    
321
def get_iso_rmsd():
322
    err_msg = num_error % ('iso_rmsd', 'positive decimal number')
323
    iso_rmsd = try_command(dos_inp.getfloat, [(ValueError, err_msg)],
324
                           'Isolated', 'iso_rmsd', fallback=0.05)
325
    if iso_rmsd <= 0.0:
326
        logger.error(err_msg)
327
        raise ValueError(err_msg)
328
    return iso_rmsd
329

    
330

    
331
def get_min_confs():
332
    err_msg = "'min_confs' should be have a boolean value (True or False)"
333
    min_confs = try_command(dos_inp.getboolean,
334
                            [(ValueError, err_msg)],
335
                            'Isolated', 'min_confs', fallback=True)
336
    return min_confs
337

    
338

    
339
def get_screen_inp_file():
340
    screen_inp_file = dos_inp.get('Screening', 'screen_inp_file')
341
    if not os.path.isfile(screen_inp_file):
342
        logger.error(f'File {screen_inp_file} not found')
343
        raise FileNotFoundError(f'File {screen_inp_file} not found')
344
    return screen_inp_file
345

    
346

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

    
371
    return sites
372

    
373

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

    
399
    return molec_ads_ctrs
400

    
401

    
402
def get_try_disso():
403
    err_msg = "try_disso should be have a boolean value (True or False)"
404
    try_disso = try_command(dos_inp.getboolean,
405
                            [(ValueError, err_msg)],
406
                            'Screening', 'try_disso', fallback=False)
407
    return try_disso
408

    
409

    
410
def get_pts_per_angle():
411
    err_msg = num_error % ('sample_points_per_angle',
412
                           'positive integer')
413
    pts_per_angle = try_command(dos_inp.getint,
414
                                [(ValueError, err_msg)],
415
                                'Screening', 'sample_points_per_angle',
416
                                fallback=3)
417

    
418
    return pts_per_angle
419

    
420

    
421
def get_coll_thrsld():
422
    err_msg = num_error % ('collision_threshold',
423
                           'positive decimal number')
424

    
425
    coll_thrsld = try_command(dos_inp.getfloat,
426
                              [(ValueError, err_msg)],
427
                              'Screening', 'collision_threshold', fallback=1.2)
428
    if coll_thrsld <= 0:
429
        logger.error(err_msg)
430
        raise ValueError(err_msg)
431

    
432
    return coll_thrsld
433

    
434

    
435
def get_screen_rmsd():
436
    err_msg = num_error % ('screen_rmsd', 'positive decimal number')
437
    screen_rmsd = try_command(dos_inp.getfloat,
438
                              [(ValueError, err_msg)],
439
                              'Screening', 'screen_rmsd', fallback=0.05)
440
    if screen_rmsd <= 0:
441
        logger.error(err_msg)
442
        raise ValueError(err_msg)
443

    
444
    return screen_rmsd
445

    
446

    
447
def get_coll_bottom_z():
448
    err_msg = num_error % ('collision_bottom_z', 'decimal number')
449
    coll_bottom_z = dos_inp.get('Screening', 'collision_bottom_z',
450
                                fallback="False")
451
    if coll_bottom_z.lower() in turn_false_answers:
452
        coll_bottom_z = False
453
    else:
454
        coll_bottom_z = try_command(float, [(ValueError, err_msg)],
455
                                    coll_bottom_z)
456

    
457
    return coll_bottom_z
458

    
459

    
460
def get_refine_inp_file():
461
    refine_inp_file = dos_inp.get('Refinement', 'refine_inp_file')
462
    if not os.path.isfile(refine_inp_file):
463
        logger.error(f'File {refine_inp_file} not found')
464
        raise FileNotFoundError(f'File {refine_inp_file} not found')
465

    
466
    return refine_inp_file
467

    
468

    
469
def get_energy_cutoff():
470
    err_msg = num_error % ('energy_cutoff', 'positive decimal number')
471
    energy_cutoff = try_command(dos_inp.getfloat,
472
                                [(ValueError, err_msg)],
473
                                'Refinement', 'energy_cutoff', fallback=0.5)
474
    if energy_cutoff < 0:
475
        logger.error(err_msg)
476
        raise ValueError(err_msg)
477
    return energy_cutoff
478

    
479

    
480
def read_input(in_file):
481
    err = False
482
    try:
483
        dos_inp.read(in_file)
484
    except MissingSectionHeaderError as e:
485
        logger.error('There are options in the input file without a Section '
486
                     'header')
487
        err = e
488
    except DuplicateOptionError as e:
489
        logger.error('There is an option in the input file that has been '
490
                     'specified more than once, possibly due to the lack of a '
491
                     'Section header')
492
        err = e
493
    except Exception as e:
494
        err = e
495
    else:
496
        err = False
497
    finally:
498
        if isinstance(err, BaseException):
499
            raise err
500

    
501
    return_vars = {}
502

    
503
    # Global
504
    if not dos_inp.has_section('Global'):
505
        logger.error(no_sect_err % 'Global')
506
        raise NoSectionError('Global')
507

    
508
    # Mandatory options
509
    # Checks whether the mandatory options 'run_type', 'code', etc. are present.
510
    glob_mand_opts = ['run_type', 'code', 'batch_q_sys']
511
    for opt in glob_mand_opts:
512
        if not dos_inp.has_option('Global', opt):
513
            logger.error(no_opt_err % (opt, 'Global'))
514
            raise NoOptionError(opt, 'Global')
515

    
516
    # Gets which sections are to be carried out
517
    isolated, screening, refinement = get_run_type()
518
    return_vars['isolated'] = isolated
519
    return_vars['screening'] = screening
520
    return_vars['refinement'] = refinement
521
    return_vars['code'] = get_code()
522
    return_vars['batch_q_sys'] = get_batch_q_sys()
523

    
524
    # Dependent options:
525
    return_vars['subm_script'] = get_subm_script()
526
    if return_vars['batch_q_sys'] != 'local' and not return_vars['subm_script']:
527
        sub_err = "'subm_script' must be provided if 'batch_q_sys' is not local"
528
        logger.error(sub_err)
529
        raise NoOptionError(opt, 'Global') # TODO Change to ValueError
530

    
531
    # Facultative options (Default/Fallback value present)
532
    return_vars['project_name'] = get_project_name()
533
    return_vars['relaunch_err'] = get_relaunch_err()
534
    return_vars['max_qw'] = get_max_qw()
535
    return_vars['special_atoms'] = get_special_atoms()
536

    
537
    # Isolated
538
    if isolated:
539
        if not dos_inp.has_section('Isolated'):
540
            logger.error(no_sect_err % 'Isolated')
541
            raise NoSectionError('Isolated')
542
        # Mandatory options
543
        # Checks whether the mandatory options are present.
544
        iso_mand_opts = ['isol_inp_file', 'molec_file']
545
        for opt in iso_mand_opts:
546
            if not dos_inp.has_option('Isolated', opt):
547
                logger.error(no_opt_err % (opt, 'Isolated'))
548
                raise NoOptionError(opt, 'Isolated')
549
        return_vars['isol_inp_file'] = get_isol_inp_file()
550
        check_inp_file(return_vars['isol_inp_file'], return_vars['code'])
551
        return_vars['molec_file'] = get_molec_file()
552

    
553
        # Facultative options (Default/Fallback value present)
554
        return_vars['cluster_magns'] = get_cluster_magns()
555
        return_vars['num_conformers'] = get_num_conformers()
556
        # return_vars['num_prom_cand'] = get_num_prom_cand()
557
        # return_vars['iso_rmsd'] = get_iso_rmsd()
558
        return_vars['min_confs'] = get_min_confs()
559

    
560
    # Screening
561
    if screening:
562
        if not dos_inp.has_section('Screening'):
563
            logger.error(no_sect_err % 'Screening')
564
            raise NoSectionError('Screening')
565
        # Mandatory options:
566
        # Checks whether the mandatory options are present.
567
        screen_mand_opts = ['sites', 'molec_ads_ctrs', 'screen_inp_file']
568
        for opt in screen_mand_opts:
569
            if not dos_inp.has_option('Screening', opt):
570
                logger.error(no_opt_err % (opt, 'Screening'))
571
                raise NoOptionError(opt, 'Screening')
572
        return_vars['screen_inp_file'] = get_screen_inp_file()
573
        return_vars['sites'] = get_sites()
574
        return_vars['molec_ads_ctrs'] = get_molec_ads_ctrs()
575

    
576
        # Facultative options (Default value present)
577
        return_vars['try_disso'] = get_try_disso()
578
        return_vars['sample_points_per_angle'] = get_pts_per_angle()
579
        return_vars['collision_threshold'] = get_coll_thrsld()
580
        # return_vars['screen_rmsd'] = get_screen_rmsd()
581
        return_vars['collision_bottom_z'] = get_coll_bottom_z()
582

    
583
    # Refinement
584
    if refinement:
585
        if not dos_inp.has_section('Refinement'):
586
            logger.error(no_sect_err % 'Refinement')
587
            raise NoSectionError('Refinement')
588
        # Mandatory options
589
        # Checks whether the mandatory options are present.
590
        ref_mand_opts = ['refine_inp_file']
591
        for opt in ref_mand_opts:
592
            if not dos_inp.has_option('Refinement', opt):
593
                logger.error(no_opt_err % (opt, 'Refinement'))
594
                raise NoOptionError(opt, 'Refinement')
595
        return_vars['refine_inp_file'] = get_refine_inp_file()
596

    
597
        # Facultative options (Default value present)
598
        return_vars['energy_cutoff'] = get_energy_cutoff()
599
        # end energy_cutoff
600

    
601
    return_vars_str = "\n\t".join([str(key) + ": " + str(val)
602
                                   for key, val in return_vars.items()])
603
    logger.info(
604
        f'Correctly read {in_file} parameters: \n\n\t{return_vars_str}\n')
605

    
606
    return return_vars
607

    
608

    
609
if __name__ == "__main__":
610
    import sys
611

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