Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ transfer_functions \ io \ tools.py: 77%
105 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
1# -*- coding: utf-8 -*-
2"""
3Created on Sat Dec 4 17:44:51 2021
5@author: jpeacock
6"""
7import json
9# =============================================================================
10# imports
11# =============================================================================
12import urllib.request as url_request
14from loguru import logger
17# =============================================================================
20def _validate_str_with_equals(input_string):
21 """
22 make sure an input string is of the format {0}={1} {2}={3} {4}={5} ...
23 Some software programs put spaces after the equals sign and that's not
24 cool. So we make the string into a readable format
26 :param input_string: input string from an edi file
27 :type input_string: string
29 :returns line_list: list of lines as ['key_00=value_00',
30 'key_01=value_01']
31 :rtype line_list: list
32 """
33 input_string = input_string.strip()
34 # remove the first >XXXXX
35 if ">" in input_string:
36 input_string = input_string[input_string.find(" ") :]
38 # check if there is a // at the end of the line
39 if input_string.find("//") > 0:
40 input_string = input_string[0 : input_string.find("//")]
42 # split the line by =
43 l_list = input_string.strip().split("=")
45 # split the remaining strings
46 str_list = []
47 for line in l_list:
48 s_list = line.strip().split()
49 for l_str in s_list:
50 str_list.append(l_str.strip())
52 # probably not a good return
53 if len(str_list) % 2 != 0:
54 # _logger.info(
55 # 'The number of entries in {0} is not even'.format(str_list))
56 return str_list
58 line_list = [
59 "{0}={1}".format(str_list[ii], str_list[ii + 1])
60 for ii in range(0, len(str_list), 2)
61 ]
63 return line_list
66# ==============================================================================
67# Index finder
68# ==============================================================================
69class index_locator(object):
70 def __init__(self, component_list):
71 self.ex = None
72 self.ey = None
73 self.hx = None
74 self.hy = None
75 self.hz = None
76 self.rhx = None
77 self.rhy = None
78 self.rhz = None
79 for ii, comp in enumerate(component_list):
80 setattr(self, comp, ii)
81 if self.rhx is None:
82 self.rhx = self.hx
83 if self.rhy is None:
84 self.rhy = self.hy
86 def __str__(self):
87 lines = ["Index Values"]
88 for k, v in self.__dict__.items():
89 if v is not None:
90 lines.append(f"\t{k} = {v}")
91 return "\n".join(lines)
93 def __repr__(self):
94 return self.__str__()
96 @property
97 def n_channels(self):
98 count = 0
99 for k, v in self.__dict__.items():
100 if "r" in k:
101 continue
102 if v is not None:
103 count += 1
105 return count
107 @property
108 def has_tipper(self):
109 if self.hz is not None:
110 return True
111 return False
113 @property
114 def has_electric(self):
115 if self.ex != None or self.ey != None:
116 return True
117 return False
119 @property
120 def input_channels(self):
121 return [self.hx, self.hy]
123 @property
124 def output_channels(self):
125 if self.has_tipper:
126 if self.has_electric:
127 return [self.hz, self.ex, self.ey]
128 return [self.hz]
129 return [self.ex, self.ey]
131 @property
132 def n_inputs(self):
133 return len(self.input_channels)
135 @property
136 def n_outputs(self):
137 return len(self.output_channels)
140def _validate_edi_lines(edi_lines) -> list[str]:
141 """
142 check for carriage returns or hard returns
144 :param edi_lines: list of edi lines
145 :type edi_lines: list
147 :returns: list of edi lines
148 :rtype: list
149 """
151 if len(edi_lines) == 1:
152 edi_lines = edi_lines[0].replace("\r", "\n").split("\n")
153 if len(edi_lines) > 1:
154 return edi_lines
155 else:
156 raise ValueError("*** EDI format not correct check file ***")
157 else:
158 return edi_lines
161def get_nm_elev(latitude, longitude):
162 """
163 Get national map elevation for a given lat and lon.
165 Queries the national map website for the elevation value.
167 :param lat: latitude in decimal degrees
168 :type lat: float
170 :param lon: longitude in decimal degrees
171 :type lon: float
173 :return: elevation (meters)
174 :rtype: float
176 :Example: ::
178 >>> import mtpy.usgs.usgs_archive as archive
179 >>> archive.get_nm_elev(35.467, -115.3355)
180 >>> 809.12
182 .. note:: Needs an internet connection to work.
184 """
185 # nm_url = (
186 # r"https://nationalmap.gov/epqs/pqs.php?"
187 # f"x={longitude:.5f}&y={latitude:.5f}&units=Meters&output=xml"
188 # )
190 nm_url = (
191 r"https://epqs.nationalmap.gov/v1/json?"
192 f"x={longitude}&y={latitude}&units=Meters&wkid=4326&includeDate=False"
193 )
194 # call the url and get the response
195 try:
196 response = url_request.urlopen(nm_url)
197 except:
198 logger.error("Could not connect to internet to get elevation data.")
199 return 0.0
201 # read the xml response and convert to a float
202 try:
203 # unpack the response to a dictionary
204 info = json.loads(response.read())
206 except json.JSONDecodeError:
207 logger.error(
208 f"Input values (latitude={latitude}, longitude={longitude}) "
209 "could not be found on US National Map."
210 )
211 return 0.0
212 try:
213 return float(info["value"])
214 except KeyError:
215 logger.warning("Could not find elevation data")
216 return 0.0
217 except ValueError:
218 logger.warning(f"Could not convert elevation {info['value']} to float")
219 return 0.0