tectonic-utils 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. tectonic_utils/.DS_Store +0 -0
  2. tectonic_utils/__init__.py +3 -0
  3. tectonic_utils/cover_picture.png +0 -0
  4. tectonic_utils/geodesy/.DS_Store +0 -0
  5. tectonic_utils/geodesy/.ruff_cache/.gitignore +1 -0
  6. tectonic_utils/geodesy/.ruff_cache/0.1.5/15663111236935520357 +0 -0
  7. tectonic_utils/geodesy/.ruff_cache/CACHEDIR.TAG +1 -0
  8. tectonic_utils/geodesy/__init__.py +0 -0
  9. tectonic_utils/geodesy/datums.py +156 -0
  10. tectonic_utils/geodesy/euler_pole.py +170 -0
  11. tectonic_utils/geodesy/fault_vector_functions.py +383 -0
  12. tectonic_utils/geodesy/haversine.py +193 -0
  13. tectonic_utils/geodesy/insar_vector_functions.py +285 -0
  14. tectonic_utils/geodesy/linear_elastic.py +231 -0
  15. tectonic_utils/geodesy/test/.DS_Store +0 -0
  16. tectonic_utils/geodesy/test/__init__.py +0 -0
  17. tectonic_utils/geodesy/test/test_conversion_functions.py +74 -0
  18. tectonic_utils/geodesy/test/test_euler_poles.py +33 -0
  19. tectonic_utils/geodesy/test/test_insar_vector_functions.py +36 -0
  20. tectonic_utils/geodesy/utilities.py +47 -0
  21. tectonic_utils/geodesy/xyz2llh.py +220 -0
  22. tectonic_utils/read_write/.DS_Store +0 -0
  23. tectonic_utils/read_write/.ruff_cache/.gitignore +1 -0
  24. tectonic_utils/read_write/.ruff_cache/0.1.5/680373307893520726 +0 -0
  25. tectonic_utils/read_write/.ruff_cache/CACHEDIR.TAG +1 -0
  26. tectonic_utils/read_write/__init__.py +0 -0
  27. tectonic_utils/read_write/general_io.py +55 -0
  28. tectonic_utils/read_write/netcdf_read_write.py +382 -0
  29. tectonic_utils/read_write/read_kml.py +68 -0
  30. tectonic_utils/read_write/test/.DS_Store +0 -0
  31. tectonic_utils/read_write/test/__init__.py +0 -0
  32. tectonic_utils/read_write/test/example_grd.grd +0 -0
  33. tectonic_utils/read_write/test/test_conversion_functions.py +40 -0
  34. tectonic_utils/read_write/test/written_example.grd +0 -0
  35. tectonic_utils/seismo/.DS_Store +0 -0
  36. tectonic_utils/seismo/.ruff_cache/.gitignore +1 -0
  37. tectonic_utils/seismo/.ruff_cache/0.1.5/12911000862714636977 +0 -0
  38. tectonic_utils/seismo/.ruff_cache/CACHEDIR.TAG +1 -0
  39. tectonic_utils/seismo/MT_calculations.py +132 -0
  40. tectonic_utils/seismo/__init__.py +0 -0
  41. tectonic_utils/seismo/moment_calculations.py +44 -0
  42. tectonic_utils/seismo/second_focal_plane.py +138 -0
  43. tectonic_utils/seismo/test/.DS_Store +0 -0
  44. tectonic_utils/seismo/test/__init__.py +0 -0
  45. tectonic_utils/seismo/test/test_WC.py +19 -0
  46. tectonic_utils/seismo/test/test_second_focal_plane.py +16 -0
  47. tectonic_utils/seismo/wells_and_coppersmith.py +167 -0
  48. tectonic_utils-0.1.2.dist-info/LICENSE.md +21 -0
  49. tectonic_utils-0.1.2.dist-info/METADATA +82 -0
  50. tectonic_utils-0.1.2.dist-info/RECORD +51 -0
  51. tectonic_utils-0.1.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,47 @@
1
+ import numpy as np
2
+
3
+
4
+ def wrap_lon(longitude):
5
+ """
6
+ Ensure longitude value is between -180° and 180° (e.g., not 240° E).
7
+
8
+ :param longitude: float
9
+ :returns: wrapped longitude, from -180° to 180°
10
+ """
11
+ if longitude > 360 or longitude < -360:
12
+ raise ValueError("longitude outside normal range (-360 to 360)")
13
+ if longitude > 180:
14
+ longitude = longitude - 360
15
+ if longitude < -180:
16
+ longitude = longitude + 360
17
+ return longitude
18
+
19
+
20
+ def get_vector_magnitude(vector):
21
+ """
22
+ Get magnitude of a vector.
23
+
24
+ :param vector: n-component vector, any units
25
+ :type vector: array_like
26
+ :return: magnitude
27
+ :rtype: float
28
+ """
29
+ total = 0
30
+ for i in range(len(vector)):
31
+ total = total + vector[i]*vector[i]
32
+ magnitude = np.sqrt(total)
33
+ return magnitude
34
+
35
+
36
+ def get_unit_vector(vec):
37
+ """
38
+ Get unit vector in the direction of a given vector.
39
+
40
+ :param vec: 3-component vector, any units
41
+ :type vec: array_like
42
+ :return: unit vector
43
+ :rtype: array_like
44
+ """
45
+ mag = np.sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2])
46
+ vec = np.divide(vec, mag)
47
+ return vec
@@ -0,0 +1,220 @@
1
+ """
2
+ Functions to convert between local enu, local llh, and global xyz coordinates.
3
+ Translated from Matlab.
4
+ """
5
+
6
+ import numpy as np
7
+ from . import datums
8
+
9
+
10
+ def xyz2llh(xyz, datum='NAD83'):
11
+ """
12
+ XYZ2LLH calculates longitude, latitude, and height from global cartesisan coordinates.
13
+ LLH = xyz2llh(XYZ, DATUM) calculates longitude(deg), latitude(deg), and height(m) on the ellipsoid
14
+ specified by DATUM from the global cartestian coordinates given in the nx3(n=number of coordinate triples)
15
+ matrix XYZ.
16
+ DATUM can either be a vector the first two elements of which give da and df,
17
+ or it can be a string containing the name of a datum that is resolved
18
+ by the function DATUMS function.
19
+ Note that longitude occupies the first row of LLH.
20
+ See DATUMS for more information on datum parameters.
21
+
22
+ :param xyz: [x, y, z]
23
+ :type xyz: numpy array
24
+ :param datum: name of datum
25
+ :type datum: string
26
+ :returns: [lon, lat, height]
27
+ :rtype: numpy array
28
+ """
29
+
30
+ # Check input arguments
31
+ if not isinstance(datum, str):
32
+ raise ValueError(f'Could not parse given datum: {datum}')
33
+ datum_array = datums.get_datums(datum)
34
+ if np.sum(np.isnan(datum_array)) > 0:
35
+ raise ValueError('Could not resolve datum name.')
36
+ da, df = datum_array[0][0], datum_array[0][1]
37
+
38
+ if np.shape(xyz)[1] != 3:
39
+ raise TypeError('Input xyz MUST be nx3.')
40
+
41
+ # Set constants
42
+ a = 6378137 - da
43
+ f = 1 / 298.2572235630 - df
44
+ b = (1-f) * a
45
+ e2 = 2 * f - np.square(f)
46
+ E2 = (np.square(a) - np.square(b)) / np.square(b)
47
+
48
+ # Calculate longitude, latitude, and height
49
+ llh = np.zeros(np.shape(xyz))
50
+ p = np.sqrt(np.square(xyz[:, 0]) + np.square(xyz[:, 1]))
51
+ llh[:, 0] = np.arctan2(xyz[:, 1], xyz[:, 0])
52
+ theta = np.arctan(np.divide((xyz[:, 2] * a), (p * b)))
53
+ llh[:, 1] = np.arctan((xyz[:, 2] + E2 * b * np.power(np.sin(theta), 3)) /
54
+ (p - e2 * a * np.power(np.cos(theta), 3)) )
55
+ N = a / np.sqrt(1 - e2 * np.square(np.sin(llh[:, 1])))
56
+ llh[:, 2] = p / np.cos(llh[:, 1]) - N
57
+
58
+ # Convert to degrees
59
+ llh[:, 0:2] = llh[:, 0:2]*57.295779513082323
60
+ return llh
61
+
62
+
63
+ def llh2xyz(llh, datum='NAD83'):
64
+ """
65
+ LLH2XYZ Calculates global cartesisan coordinates from longitude, latitude, and height.
66
+ XYZ=llh2xyz(llh,DATUM) calculates global cartestian coordinates
67
+ given the nx3 (n = number of coordinate triples) matrix LLH that contains
68
+ longitude (deg), latitude (deg), and height (m) on the ellipsoid
69
+ specified by DATUM. DATUM can either be a vector the first two elements
70
+ of which give da and df, or it can be a string containing the name of a
71
+ datum that is resolved by the function DATUMS function.
72
+ Note that longitude occupies the first row of LLH.
73
+ See DATUMS for more information on datum parameters.
74
+
75
+ :param llh: [lon, lat, height]
76
+ :type llh: numpy array
77
+ :param datum: name of datum
78
+ :type datum: string
79
+ """
80
+
81
+ # Check input arguments
82
+ if not isinstance(datum, str):
83
+ raise ValueError(f'Could not parse given datum: {datum}')
84
+ datum_array = datums.get_datums(datum)
85
+ if np.sum(np.isnan(datum_array)) > 0:
86
+ raise ValueError(f'Could not resolve datum name: {datum}')
87
+ da, df = datum_array[0][0], datum_array[0][1]
88
+
89
+ if np.shape(llh)[1] != 3:
90
+ raise TypeError('Input llh MUST be nx3.')
91
+
92
+ # Ellipsoid parameters
93
+ a = 6378137 - da
94
+ f = 1 / 298.257223563 - df
95
+ b = (1-f) * a
96
+
97
+ # Convert degrees to radians
98
+ phi = llh[:, 1] * np.pi / 180 # lat
99
+ lam = llh[:, 0] * np.pi / 180 # lon
100
+
101
+ # Convert llh to xyz
102
+ XYZ = np.zeros(np.shape(llh))
103
+ N = np.square(a) / np.sqrt(np.square(a) * np.square(np.cos(phi)) + np.square(b) * np.square(np.sin(phi)))
104
+ XYZ[:, 0] = (N + llh[:, 2]) * np.cos(phi) * np.cos(lam)
105
+ XYZ[:, 1] = (N + llh[:, 2]) * np.cos(phi) * np.sin(lam)
106
+ XYZ[:, 2] = (np.square(b) * N / np.square(a) + llh[:, 2] ) * np.sin(phi)
107
+ return XYZ
108
+
109
+
110
+ def xyz2enum(origin):
111
+ """
112
+ XYZ2ENUM Returns a global to local transformation matrix.
113
+ T=xyz2enum(ORIGIN) Returns a transformation matrix that
114
+ tranforms coordinates in a global ECEF cartesian system
115
+ into to a local coordinate system aligned with the geographic
116
+ directions at the position ORIGIN. ORIGIN should contain a
117
+ longitude and a latitude pair (degrees). T is 3x3.
118
+
119
+ :param origin: [longitude, latitude]
120
+ :type origin: np array
121
+ """
122
+
123
+ # Check input arguments
124
+ if len(origin) < 2:
125
+ raise ValueError('Input origin must have 2 elements, longitude and latitude (degrees).')
126
+
127
+ # Convert to radians and evaluate trigonometric functions
128
+ origin = np.multiply(origin, np.pi / 180)
129
+ s = np.sin(origin)
130
+ c = np.cos(origin)
131
+
132
+ # Make transformation matrix
133
+ T = np.array([[-s[0], c[0], 0],
134
+ [-s[1]*c[0], -s[1]*s[0], c[1]],
135
+ [c[1]*c[0], c[1]*s[0], s[1]]])
136
+ return T
137
+
138
+
139
+ def xyz2enu(d, origin, dcov=None):
140
+ """
141
+ XYZ2ENU Transforms from global cartestian to local cartesian.
142
+ [E,ECOV]=xyz2enu(D,DCOV,ORIGIN) transforms data vector D and
143
+ data covariance DCOV from a global cartesian (XYZ) coordinate
144
+ system to a local coordinate system aligned with the geographic
145
+ directions at the position ORIGIN.
146
+ D should be either 3nx1 or 3xn (n = number of individual vectors).
147
+ DCOV should be 3nx3n.
148
+ ORIGIN should be a vector of length 2 or 3. If length 2, ORIGIN
149
+ is taken as a longitude, latitude pair (degrees); if length 3,
150
+ ORIGIN is taken as an XYZ station position. E is matrix (vector)
151
+ of transformed coordinates the same size as input D. ECOV is a
152
+ matrix containing the transformed covariance.
153
+ E=xyz2enu(D,ORIGIN) behaves as above without a data covariance matrix.
154
+
155
+ :param d: nx3 np array of x, y, z values
156
+ :type d: numpy array
157
+ :param origin: 1x3 np array (x, y, z) or 1x2 np.array (lon, lat)
158
+ :type origin: numpy array
159
+ :param dcov: 3x3 np array
160
+ :type dcov: numpy array
161
+ """
162
+
163
+ # Check input arguments
164
+ if len(origin) > 2:
165
+ origin = np.reshape(origin, (1, 3))
166
+ origin = xyz2llh(origin)
167
+ origin = origin[0] # 1x3 1D array, contains llh
168
+
169
+ # Make transformation matrix
170
+ Tm = xyz2enum(origin)
171
+
172
+ # Transform
173
+ e = np.dot(Tm, d.T)
174
+ if dcov is not None:
175
+ ecov = np.dot(np.dot(Tm, dcov), Tm.T)
176
+ else:
177
+ ecov = None
178
+ return e.T, ecov
179
+
180
+
181
+ def enu2xyz(d, origin, dcov=None):
182
+ """
183
+ ENU2XYZ Transforms from global cartestian to local cartesian.
184
+ [E,ECOV]=xyz2enu(D,DCOV,ORIGIN) transforms data vector D and
185
+ data covariance DCOV from a local cartesian (ENU) coordinate
186
+ system aligned with the geographic directions at the position ORIGIN
187
+ to a global (XYZ) coordinate system.
188
+ D should be either 3nx1 or 3xn (n = number of individual vectors).
189
+ DCOV should be 3nx3n.
190
+ ORIGIN should be a vector of length 2 or 3. If length 2, ORIGIN
191
+ is taken as a longitude, latitude pair (degrees); if length 3,
192
+ ORIGIN is taken as an XYZ station position. E is matrix (vector)
193
+ of transformed coordinates the same size as input D. ECOV is a
194
+ matrix containing the transformed covariance.
195
+ E=xyz2enu(D,ORIGIN) behaves as above without a data covariance matrix.
196
+
197
+ :param d: nx3 np array of e, n, u values
198
+ :type d: numpy array
199
+ :param origin: 1x3 np array (x, y, z) or 1x2 np.array (lon, lat)
200
+ :type origin: numpy array
201
+ :param dcov: 3x3 np array
202
+ :type dcov: numpy array
203
+ """
204
+ # Check input arguments
205
+ if len(origin) > 2:
206
+ origin = np.reshape(origin, (1, 3))
207
+ origin = xyz2llh(origin)
208
+ origin = origin[0] # 1x3 1D array, contains llh
209
+
210
+ # Make transformation matrix
211
+ Tm = xyz2enum(origin)
212
+ Tminv = np.linalg.inv(Tm)
213
+
214
+ # Transform
215
+ e = np.dot(Tminv, d.T)
216
+ if dcov is not None:
217
+ ecov = np.dot(np.dot(Tminv, dcov), Tminv.T)
218
+ else:
219
+ ecov = None
220
+ return e.T, ecov
Binary file
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
File without changes
@@ -0,0 +1,55 @@
1
+ """
2
+ Functions to read common file types into structures in Python.
3
+ Example: a multi-segment file with polygons or lines, as could be used in GMT.
4
+ """
5
+
6
+
7
+ def read_gmt_multisegment_latlon(input_file, split_delimiter=' '):
8
+ """
9
+ Generalized GMT multisegment file reader.
10
+ Returns lon and lat in a list of lists, each element with a single segment.
11
+
12
+ :param input_file: name of input file
13
+ :type input_file: string
14
+ :param split_delimiter: delimiter between values on the same line, defaults to space
15
+ :type split_delimiter: string, optional
16
+ :returns: list of lons, list of lats
17
+ :rtype: list
18
+ """
19
+ print("reading gmt multisegment file %s" % input_file)
20
+ ifile = open(input_file)
21
+ lon_collection, lat_collection = [], []
22
+ lon_temp, lat_temp = [], []
23
+ for line in ifile:
24
+ if line.split()[0] == '>>' or line.split()[0] == '>':
25
+ if lon_temp:
26
+ lon_collection.append(lon_temp)
27
+ lat_collection.append(lat_temp)
28
+ lon_temp, lat_temp = [], []
29
+ continue
30
+ else:
31
+ temp = line.split(split_delimiter)
32
+ lon_temp.append(float(temp[0]))
33
+ lat_temp.append(float(temp[1]))
34
+ lon_collection.append(lon_temp)
35
+ lat_collection.append(lat_temp)
36
+ return lon_collection, lat_collection
37
+
38
+
39
+ def write_gmt_multisegment(list_of_coords_segments, filename):
40
+ """
41
+ Write a list of lists of coordiantes into a GMT-compatible multi-segment file
42
+ [(-115.5650522767964, 33.11974272741214, 0.0),
43
+ (-115.5642209309202, 33.12270979703938, 0.0),
44
+ (-115.5637985114591, 33.12561963960839, 0.0)]
45
+
46
+ :param list_of_coords_segments: list of lists, or list of tuples
47
+ :param filename: string, name of output file
48
+ """
49
+ print("Writing file %s " % filename)
50
+ with open(filename, 'w') as ofile:
51
+ for segment in list_of_coords_segments:
52
+ ofile.write('>\n')
53
+ for coordinate in segment:
54
+ ofile.write("%f %f \n" % (coordinate[0], coordinate[1]))
55
+ return