Coverage for tcvx21/grillix_post/components/namelist_reader_m.py: 98%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Implementation of a reader for Fortran namelist readers, which can be used to interface with parameter files
3"""
5from collections import defaultdict
6from os import name
7from pathlib import Path
8import f90nml
9from tempfile import NamedTemporaryFile
10import fnmatch
13def read_fortran_namelist(path: Path):
14 """
15 Fortran namelist reader, using the f90nml module.
17 If the '+' character is detected in the source file, a temporary file is made
18 which removes '+'. This prevents a possible error in the namelist reading.
19 """
21 assert path.exists()
23 with open(path, 'r') as file:
24 contents = file.read()
26 if "+" in contents:
27 contents = contents.replace("+", "")
29 temp_path = Path(NamedTemporaryFile(delete=False).name)
31 with open(temp_path, 'w') as temp_file:
32 temp_file.write(contents)
34 namelist = f90nml_read_file(temp_path)
36 # Remove the temporary file
37 temp_path.unlink()
39 else:
40 namelist = f90nml_read_file(path)
42 return convert_dict_to_defaultdict_recursive(namelist)
45def f90nml_read_file(filename: Path):
46 """
47 Uses the f90nml library to read the namelist, and then returns a defaultdict of the result
48 """
50 namelist = f90nml.read(str(filename)).todict()
52 return namelist
55def convert_dict_to_defaultdict_recursive(input_dict):
56 """
57 Recursively converts all dictionaries, and values which are dictionaries, into defaultdicts
58 """
60 input_dict = defaultdict(list, input_dict)
62 for key, item in input_dict.items():
63 if isinstance(item, dict):
64 input_dict[key] = convert_dict_to_defaultdict_recursive(item)
66 return input_dict
69def convert_params_filepaths(parameter_file_path: Path, params: dict):
70 """
71 Adds parameters in linked namelists to the base parameter dictionary
72 """
73 params_paths = {
74 'grid_params_path' : 'params_grid',
75 'map_params_path': 'params_map',
76 'init_params_path': 'params_init',
77 'trace_params_path': 'params_trace',
78 'tstep_params_path': 'params_tstep',
79 'physmod_params_path': 'params_physmod',
80 'bndconds_params_path': 'params_bndconds',
81 'bufferz_params_path': 'params_bufferz',
82 'floors_params_path': 'params_floors',
83 'multigrid_params_path': 'params_multigrid',
84 'pimsolver_params_path': 'params_pimsolver',
85 'penalisation_params_path': 'params_penalisation',
86 'diags_params_path': 'params_diags',
87 'srcsnk_params_path': 'params_srcsnk',
88 'tempdev_params_path': 'params_tempdev',
89 'neutrals_params_path': 'params_neutrals',
90 'iotrunk_params_path': 'params_iotrunk'
91 }
93 for key, path in params['params_filepaths'].items():
95 pointer_filepath = parameter_file_path.parent / path
96 assert pointer_filepath.exists()
97 pointer_params = read_fortran_namelist(pointer_filepath)
99 if key == 'equi_init_params_path':
100 equi_params = fnmatch.filter(pointer_params.keys(), 'equi_*_params')
101 assert len(equi_params) == 1
103 params[equi_params[0]] = pointer_params[equi_params[0]]
104 else:
105 new_key = params_paths[key]
106 if not new_key in pointer_params.keys():
107 print(f"No match for {new_key}. Setting to []")
108 else:
109 params[new_key] = pointer_params[new_key]
111 return params