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

43 statements  

1""" 

2Implementation of a reader for Fortran namelist readers, which can be used to interface with parameter files 

3""" 

4 

5from collections import defaultdict 

6from os import name 

7from pathlib import Path 

8import f90nml 

9from tempfile import NamedTemporaryFile 

10import fnmatch 

11 

12 

13def read_fortran_namelist(path: Path): 

14 """ 

15 Fortran namelist reader, using the f90nml module. 

16 

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 """ 

20 

21 assert path.exists() 

22 

23 with open(path, 'r') as file: 

24 contents = file.read() 

25 

26 if "+" in contents: 

27 contents = contents.replace("+", "") 

28 

29 temp_path = Path(NamedTemporaryFile(delete=False).name) 

30 

31 with open(temp_path, 'w') as temp_file: 

32 temp_file.write(contents) 

33 

34 namelist = f90nml_read_file(temp_path) 

35 

36 # Remove the temporary file 

37 temp_path.unlink() 

38 

39 else: 

40 namelist = f90nml_read_file(path) 

41 

42 return convert_dict_to_defaultdict_recursive(namelist) 

43 

44 

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 """ 

49 

50 namelist = f90nml.read(str(filename)).todict() 

51 

52 return namelist 

53 

54 

55def convert_dict_to_defaultdict_recursive(input_dict): 

56 """ 

57 Recursively converts all dictionaries, and values which are dictionaries, into defaultdicts 

58 """ 

59 

60 input_dict = defaultdict(list, input_dict) 

61 

62 for key, item in input_dict.items(): 

63 if isinstance(item, dict): 

64 input_dict[key] = convert_dict_to_defaultdict_recursive(item) 

65 

66 return input_dict 

67 

68 

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 } 

92 

93 for key, path in params['params_filepaths'].items(): 

94 

95 pointer_filepath = parameter_file_path.parent / path 

96 assert pointer_filepath.exists() 

97 pointer_params = read_fortran_namelist(pointer_filepath) 

98 

99 if key == 'equi_init_params_path': 

100 equi_params = fnmatch.filter(pointer_params.keys(), 'equi_*_params') 

101 assert len(equi_params) == 1 

102 

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] 

110 

111 return params