Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ transfer_functions \ io \ jfiles \ metadata \ header.py: 92%

78 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-10 00:11 -0800

1# ===================================================== 

2# Imports 

3# ===================================================== 

4from typing import Annotated 

5 

6from pydantic import Field 

7 

8from mt_metadata.common import BasicLocation 

9 

10from . import BirrpAngles, BirrpBlock, BirrpParameters 

11 

12 

13# ===================================================== 

14class Header(BasicLocation): 

15 title: Annotated[ 

16 str, 

17 Field( 

18 default="", 

19 description="title of file", 

20 alias=None, 

21 json_schema_extra={ 

22 "units": None, 

23 "required": True, 

24 "examples": ["BIRRP Version 5 basic mode output"], 

25 }, 

26 ), 

27 ] 

28 

29 station: Annotated[ 

30 str, 

31 Field( 

32 default="", 

33 description="station name", 

34 alias=None, 

35 json_schema_extra={ 

36 "units": None, 

37 "required": True, 

38 "examples": ["mt001"], 

39 }, 

40 ), 

41 ] 

42 

43 azimuth: Annotated[ 

44 float, 

45 Field( 

46 default=0.0, 

47 description="rotation of full impedance tensor", 

48 alias=None, 

49 json_schema_extra={ 

50 "units": "degrees", 

51 "required": True, 

52 "examples": ["0"], 

53 }, 

54 ), 

55 ] 

56 

57 birrp_parameters: Annotated[ 

58 BirrpParameters, 

59 Field( 

60 default_factory=BirrpParameters, # type: ignore 

61 description="BIRRP parameters", 

62 alias=None, 

63 json_schema_extra={ 

64 "units": None, 

65 "required": True, 

66 "examples": ["BirrpParameters(...)"], 

67 }, 

68 ), 

69 ] 

70 

71 data_blocks: Annotated[ 

72 list[BirrpBlock], 

73 Field( 

74 default_factory=list, 

75 description="BIRRP data blocks", 

76 alias=None, 

77 json_schema_extra={ 

78 "units": None, 

79 "required": True, 

80 "examples": ["BirrpBlock(...)"], 

81 }, 

82 ), 

83 ] 

84 

85 angles: Annotated[ 

86 list[BirrpAngles], 

87 Field( 

88 default_factory=list, 

89 description="BIRRP angles", 

90 alias=None, 

91 json_schema_extra={ 

92 "units": None, 

93 "required": True, 

94 "examples": ["BirrpAngles(...)"], 

95 }, 

96 ), 

97 ] 

98 

99 def _read_header_line(self, line: str) -> dict: 

100 """ 

101 Parse a single header line from the BIRRP output. 

102 

103 Parameters 

104 ---------- 

105 line : str 

106 A line from the BIRRP header. 

107 

108 Returns 

109 ------- 

110 dict 

111 A dictionary with the parsed key-value pairs. 

112 """ 

113 

114 line = " ".join(line[1:].strip().split()) 

115 

116 new_line = "" 

117 

118 # need to restructure the string so its readable, at least the way 

119 # that birrp outputs the file 

120 e_find = 0 

121 for ii in range(len(line)): 

122 if line[ii] == "=": 

123 e_find = ii 

124 new_line += line[ii] 

125 elif line[ii] == " ": 

126 if abs(e_find - ii) == 1: 

127 pass 

128 else: 

129 new_line += "," 

130 else: 

131 new_line += line[ii] 

132 # now that we have a useful line, split it into its parts 

133 line_list = new_line.split(",") 

134 

135 # try to split up the parts into a key=value setup 

136 # and try to make the values floats if they can be 

137 l_dict = {} 

138 key = "null" 

139 for ll in line_list: 

140 ll_list = ll.split("=") 

141 if len(ll_list) == 1: 

142 continue 

143 # some times there is just a list of numbers, need a way to read 

144 # that. 

145 if len(ll_list) != 2: 

146 if type(l_dict[key]) is not list: 

147 l_dict[key] = list([l_dict[key]]) 

148 try: 

149 l_dict[key].append(float(ll)) 

150 except ValueError: 

151 l_dict[key].append(ll) 

152 else: 

153 key = ll_list[0] 

154 try: 

155 value = float(ll_list[1]) 

156 except ValueError: 

157 value = ll_list[1] 

158 l_dict[key] = value 

159 return l_dict 

160 

161 def read_header(self, j_lines: list[str]) -> None: 

162 """ 

163 Parsing the header lines of a j-file to extract processing information. 

164 

165 Parameters 

166 ---------- 

167 j_lines : str 

168 The lines of the j-file as a string. 

169 

170 """ 

171 

172 self.data_blocks = [] 

173 self.angles = [] 

174 

175 header_lines = [j_line for j_line in j_lines if "#" in j_line] 

176 self.title = header_lines[0][1:].strip() 

177 

178 fn_count = -1 

179 theta_count = -1 

180 # put the information into a dictionary 

181 for h_line in header_lines[1:]: 

182 h_dict = self._read_header_line(h_line) 

183 for key, value in h_dict.items(): 

184 if key in [ 

185 "filnam", 

186 "nskip", 

187 "nread", 

188 "ncomp", 

189 "indices", 

190 "nfil", 

191 ]: 

192 if key in ["nfil"]: 

193 fn_count += 1 

194 if len(self.data_blocks) != fn_count + 1: 

195 self.data_blocks.append(BirrpBlock()) 

196 self.data_blocks[fn_count].update_attribute(key, value) 

197 # if its the line of angles, put them all in a list with a unique key 

198 elif key in ["theta1", "theta2", "phi"]: 

199 if key == "theta1": 

200 theta_count += 1 

201 if len(self.angles) != theta_count + 1: 

202 self.angles.append(BirrpAngles()) 

203 self.angles[theta_count].update_attribute(key, value) 

204 else: 

205 self.birrp_parameters.update_attribute(key, value) 

206 

207 def read_metadata(self, j_lines: list[str]) -> None: 

208 """ 

209 Read in the metadata of the station, or information of station 

210 logistics like: lat, lon, elevation 

211 

212 Parameters 

213 ---------- 

214 j_lines : str 

215 The lines of the j-file as a string. 

216 

217 Not really needed for a birrp output since all values are nan's 

218 """ 

219 

220 metadata_lines = [j_line for j_line in j_lines if ">" in j_line] 

221 

222 for m_line in metadata_lines: 

223 m_list = m_line.strip().split("=") 

224 m_key = m_list[0][1:].strip().lower() 

225 try: 

226 m_value = float(m_list[0].strip()) 

227 except ValueError: 

228 m_value = 0.0 

229 self.update_attribute(m_key, m_value)