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,285 @@
1
+ """
2
+ Useful utilities for look vectors and coordinate systems.
3
+ """
4
+
5
+ import numpy as np
6
+
7
+
8
+ def bearing_to_cartesian(heading):
9
+ """
10
+ Bearing (heading from North) to cartesian orientation CCW from east.
11
+
12
+ :param heading: CW from North, in degrees
13
+ :type heading: float
14
+ :returns: Cartesian direction, CCW from East, in degrees
15
+ :rtype: float
16
+ """
17
+ return 90 - heading
18
+
19
+
20
+ def cartesian_to_heading(cartesian_angle):
21
+ """
22
+ Cartesian orientation (CCW from east) to heading (CW from north).
23
+
24
+ :param cartesian_angle: CCW from East, in degrees
25
+ :type cartesian_angle: float
26
+ :returns: heading direction, CW from North, in degrees
27
+ :rtype: float
28
+ """
29
+ return 90 - cartesian_angle
30
+
31
+
32
+ def complement_angle(angle):
33
+ """
34
+ 90 minus angle, in degrees.
35
+
36
+ :param angle: degrees
37
+ :returns: angle in degrees
38
+ """
39
+ return 90 - angle
40
+
41
+
42
+ def cartesian_to_ccw_from_north(angle):
43
+ """
44
+ angle minus 90, in degrees.
45
+
46
+ :param angle: degrees
47
+ :returns: angle in degrees
48
+ """
49
+ return angle - 90
50
+
51
+
52
+ def rotate_vector_by_angle(x0, y0, theta):
53
+ """
54
+ rotate a vector by an angle theta, in degrees CCW from East.
55
+
56
+ :param x0: x component of vector
57
+ :type x0: float
58
+ :param y0: y component of vector
59
+ :type y0: float
60
+ :param theta: angle to rotate by, in degrees CCW from East like the mathematical definition
61
+ :type theta: float
62
+ :returns: xprime, yprime
63
+ :rtype: float, float
64
+ """
65
+ x_prime = x0 * np.cos(np.deg2rad(-theta)) - y0 * np.sin(np.deg2rad(-theta))
66
+ y_prime = x0 * np.sin(np.deg2rad(-theta)) + y0 * np.cos(np.deg2rad(-theta))
67
+ return x_prime, y_prime
68
+
69
+
70
+ def normalize_vector(lkve, lkvn, lkvu):
71
+ """Take a 3-component vector and normalize its components to a unit vector."""
72
+ east_sq = np.square(lkve)
73
+ north_sq = np.square(lkvn)
74
+ up_sq = np.square(lkvu)
75
+ sumarray = np.add(east_sq, north_sq)
76
+ sumarray = np.add(sumarray, up_sq)
77
+ magnitude = np.sqrt(sumarray)
78
+ norm_lkve = np.divide(lkve, magnitude)
79
+ norm_lkvn = np.divide(lkvn, magnitude)
80
+ norm_lkvu = np.divide(lkvu, magnitude)
81
+ return norm_lkve, norm_lkvn, norm_lkvu
82
+
83
+
84
+ def get_unit_vector_from_angle(angle):
85
+ """
86
+ Get the unit vector associated with a cartesian angle (CCW from east in degrees).
87
+
88
+ :param angle: degrees CW from North
89
+ :returns: list of two floats, x-component and y-component of unit vector
90
+ """
91
+ xcomponent, ycomponent = np.cos(np.deg2rad(angle)), np.sin(np.deg2rad(angle))
92
+ return [xcomponent, ycomponent]
93
+
94
+
95
+ def get_unit_vector_from_heading(heading):
96
+ """
97
+ Get the unit vector associated with a heading angle (CW from north in degrees).
98
+
99
+ :param heading: degrees CW from North
100
+ :returns: list of two floats, x-component and y-component of unit vector
101
+ """
102
+ cartesian_angle = bearing_to_cartesian(heading)
103
+ [xcomponent, ycomponent] = get_unit_vector_from_angle(cartesian_angle)
104
+ return [xcomponent, ycomponent]
105
+
106
+
107
+ def calc_rdr_azimuth_incidence_from_lkv_plane_down(lkve, lkvn, lkvu):
108
+ """
109
+ Function especially for UAVSAR interferograms to extract the incidence angle from lkv products.
110
+ lkve, lkvn, lkvu describe vector from plane to ground.
111
+ Convention: Azimuth angle measured from North in Anti-clockwise direction, in degrees, from ground to plane.
112
+ Convention: Incidence angle measured from vertical at target.
113
+ (aka degrees from vertical at satellite) (always +ve), in degrees.
114
+
115
+ :param lkve: e component of look vector FROM PLANE TO GROUND
116
+ :type lkve: float
117
+ :param lkvn: n component of look vector FROM PLANE TO GROUND
118
+ :type lkvn: float
119
+ :param lkvu: u component of look vector FROM PLANE TO GROUND
120
+ :type lkvu: float
121
+ :returns: azimuth, incidence, angles in degrees
122
+ :rtype: float, float
123
+ """
124
+
125
+ east_sq = np.square(lkve)
126
+ north_sq = np.square(lkvn)
127
+ sumarray = np.add(east_sq, north_sq)
128
+ magnitude = np.sqrt(sumarray)
129
+ azimuth_standard = np.arctan2(-lkvn, -lkve) # azimuth is negative the direction of look vector from plane down
130
+ azimuth_standard = np.rad2deg(azimuth_standard)
131
+ azimuth = np.add(azimuth_standard, -90)
132
+
133
+ incidence = np.arctan2(magnitude, -lkvu)
134
+ incidence = np.rad2deg(incidence)
135
+ return azimuth, incidence
136
+
137
+
138
+ def calc_lkv_from_rdr_azimuth_incidence(azimuth, incidence):
139
+ """
140
+ Function especially for ISCE interferograms to extract the lkv from azimuth/incidence.
141
+ Convention: Azimuth angle measured from North in Anti-clockwise direction, in degrees, from ground to plane.
142
+ Convention: Incidence angle measured from vertical at target.
143
+ (aka degrees from vertical at satellite) (always +ve), in degrees.
144
+ lkve, lkvn, lkvu describe vector from ground to plane.
145
+
146
+ :param azimuth: CCW from north angle of vector from ground to plane, in degrees (ISCE LOS.RDR convention)
147
+ :type azimuth: float
148
+ :param incidence: angle from look vector to vertical, measured at the target (aka deg. from vertical at satellite)
149
+ :type incidence: float
150
+ :returns: lkve, lkvn, lkvu, unit vector from ground to plane
151
+ """
152
+
153
+ azimuth_standard = np.add(azimuth, 90) # turning the CCW from N into CCW from East
154
+ azimuth_rad = np.deg2rad(azimuth_standard)
155
+ incidence_rad = np.deg2rad(incidence)
156
+ lkv_u = np.cos(incidence_rad)
157
+ lkv_n = np.sin(incidence_rad) * np.sin(azimuth_rad)
158
+ lkv_e = np.sin(incidence_rad) * np.cos(azimuth_rad)
159
+ return lkv_e, lkv_n, lkv_u
160
+
161
+
162
+ def look_vector2flight_incidence_angles(lkv_e, lkv_n, lkv_u, look_direction='right'):
163
+ """
164
+ Compute incidence and azimuth from 3-component look vector.
165
+ For left-looking platform, subtract 180 from the resulting azimuth.
166
+ The inputs can be either scalars or numpy arrays.
167
+ lkv_e, lkv_n, lkv_u are the components of the look vector from ground to satellite.
168
+ incidence angle is angle between look vector and vertical in degrees.
169
+ Flight angle is clockwise from north in degrees.
170
+
171
+ :param lkv_e: e component of look vector from ground to satellite
172
+ :type lkv_e: float or numpy array
173
+ :param lkv_n: n component of look vector from ground to satellite
174
+ :type lkv_n: float or numpy array
175
+ :param lkv_u: u component of look vector from ground to satellite
176
+ :type lkv_u: float or numpy array
177
+ :param look_direction: look direction of the SAR platform, must be 'right' or 'left'
178
+ :type look_direction: string
179
+ :returns: [flight_angle, incidence_angle] in degrees
180
+ :rtype: list of two objects, either floats or numpy arrays
181
+ """
182
+
183
+ # Stack into a 3D array: shape (M, N, 3)
184
+ unit_lkv = np.stack((lkv_e, lkv_n, lkv_u), axis=-1) # shape (M, N, 3)
185
+
186
+ # Normalize each 3-component vector (broadcasting norm across last axis)
187
+ norms = np.linalg.norm(unit_lkv, axis=-1, keepdims=True) # shape (M, N, 1)
188
+ unit_lkv_normalized = unit_lkv / norms # shape (M, N, 3)
189
+
190
+ # Dot product with vertical vector [0, 0, 1]
191
+ dotproduct = unit_lkv_normalized[..., 2] # Extract just the "up" component
192
+
193
+ # Incidence and Azimuth: angle from vertical, angle on horizontal plane
194
+ incidence_angle = np.rad2deg(np.arccos(dotproduct))
195
+ lkv_horiz_angle = np.arctan2(lkv_n, lkv_e) # cartesian angle of horiz look-vec. (negative small # for DESC)
196
+ heading_deg = cartesian_to_heading(np.rad2deg(lkv_horiz_angle))
197
+ if look_direction == 'right':
198
+ flight_angle = heading_deg + 90 # satellite flies 90 degrees away from look vector direction, right-looking
199
+ elif look_direction == 'left':
200
+ flight_angle = heading_deg - 90 # satellite flies 90 degrees away from look vector direction, left-looking
201
+ else:
202
+ raise (ValueError("ERROR! Provided look direction of %s must be right or left" % look_direction))
203
+ return [flight_angle, incidence_angle]
204
+
205
+
206
+ def flight_incidence_angles2look_vector(flight_angle, incidence_angle, look_direction='right'):
207
+ """
208
+ Compute look vector components from azimuth and incidence.
209
+ lkv_e, lkv_n, lkv_u are the components of the look vector from ground to satellite.
210
+ The inputs can be either scalars or numpy arrays.
211
+
212
+ :param flight_angle: heading, clockwise from north, in degrees
213
+ :type flight_angle: float or numpy array
214
+ :param incidence_angle: angle between look vector and vertical, in degrees
215
+ :type incidence_angle: float or numpy array
216
+ :param look_direction: look direction of the SAR platform, must be 'right' or 'left'
217
+ :type look_direction: string
218
+ :returns: [lkv_e, lkv_n, lkv_u]
219
+ :rtype: list of three objects, either floats or numpy arrays
220
+ """
221
+ if look_direction == 'right':
222
+ lk_heading = flight_angle - 90 # heading, 90 degrees to the right of the satellite
223
+ elif look_direction == 'left':
224
+ lk_heading = flight_angle + 90 # heading, 90 degrees to the left of the satellite
225
+ else:
226
+ raise (ValueError("ERROR! Provided look direction of %s must be right or left" % look_direction))
227
+ horizontal_lkv = np.sin(np.deg2rad(incidence_angle))
228
+ lkv_u = np.cos(np.deg2rad(incidence_angle))
229
+ lkv_cartesian_angle = bearing_to_cartesian(lk_heading)
230
+ lkv_e = horizontal_lkv * np.cos(np.deg2rad(lkv_cartesian_angle))
231
+ lkv_n = horizontal_lkv * np.sin(np.deg2rad(lkv_cartesian_angle))
232
+ return [lkv_e, lkv_n, lkv_u]
233
+
234
+
235
+ def def3D_into_LOS(U_e, U_n, U_u, flight_angle, incidence_angle, look_direction='right'):
236
+ r"""
237
+ Fialko, 2001, equation to project relative deformation into the LOS.
238
+
239
+ .. math:: d_{los} = [U_n \sin(\phi) - U_e \cos(\phi)]*\sin(\lambda) + U_u \cos(\lambda).
240
+
241
+ where
242
+ lambda = incidence angle,
243
+ phi = flight heading, and
244
+ [U_e, U_n, U_u] are the east, north, and up components of the deformation.
245
+
246
+ :param U_e: east component of deformation
247
+ :type U_e: float
248
+ :param U_n: north component of deformation
249
+ :type U_n: float
250
+ :param U_u: vertical component of deformation
251
+ :type U_u: float
252
+ :param flight_angle: azimuth of satellite heading vector in degrees, CW from north
253
+ :type flight_angle: float
254
+ :param incidence_angle: local incidence angle at the reflector (angle from the vertical), in degrees
255
+ :type incidence_angle: float
256
+ :param look_direction: 'left' or 'right' (default 'right')
257
+ :type look_direction: string
258
+ :returns: los deformation (in same units as U_e)
259
+ :rtype: float
260
+ """
261
+ phi = np.deg2rad(flight_angle)
262
+ lamda = np.deg2rad(incidence_angle)
263
+ if look_direction == 'right':
264
+ d_los = ((U_n * np.sin(phi) - U_e * np.cos(phi)) * np.sin(lamda) + U_u * np.cos(lamda))
265
+ elif look_direction == 'left':
266
+ d_los = (-(U_n * np.sin(phi) - U_e * np.cos(phi)) * np.sin(lamda) + U_u * np.cos(lamda))
267
+ else:
268
+ raise ValueError("Error! parameter look_direction must be 'right' or 'left', not %s" % look_direction)
269
+ return d_los
270
+
271
+
272
+ def proj_los_into_vertical_no_horiz(los, lkv):
273
+ """
274
+ Project LOS deformation into a pseudo-vertical deformation,
275
+ assuming horizontal deformation is zero.
276
+ Compute the vertical deformation needed to produce given LOS deformation.
277
+
278
+ :param los: float
279
+ :param lkv: list of 3 floats, normalized look vector components E, N, U
280
+ """
281
+ lkv_horizontal = np.sqrt(lkv[0]*lkv[0] + lkv[1]*lkv[1])
282
+ lkv_vertical = lkv[2]
283
+ incidence_angle = np.arctan(lkv_horizontal/lkv_vertical) # incidence angle from the vertical
284
+ pseudo_vertical_disp = los / np.cos(incidence_angle) # assuming no horizontal data contributes to LoS
285
+ return pseudo_vertical_disp
@@ -0,0 +1,231 @@
1
+ """
2
+ Theory: Conversion functions between the six fundamental material parameters in 3D Linear elasticity.
3
+ Example: https://en.wikipedia.org/wiki/Elastic_modulus
4
+ """
5
+
6
+ import numpy as np
7
+
8
+
9
+ def get_constants_from_bulk_and_youngs(K, E):
10
+ """
11
+ Given Bulk (K) and Young's (E) moduli, what are the other elastic constants?
12
+
13
+ :param K: bulk modulus
14
+ :param E: young's modulus
15
+ :returns: [lame1, G, poisson's ratio, and p-wave modulus]
16
+ :rtype: list of 4 floats
17
+ """
18
+ lame1 = (3*K * (3*K - E)) / (9*K - E)
19
+ G = (3*K*E) / (9*K - E)
20
+ pr = (3*K - E) / (6*K)
21
+ M = (3*K * (3*K + E) ) / (9*K - E)
22
+ return [lame1, G, pr, M]
23
+
24
+
25
+ def get_constants_from_bulk_and_lame1(K, lame1):
26
+ """
27
+ Given Bulk modulus (K) and lame1 (lambda), what are the other elastic constants?
28
+
29
+ :param K: bulk modulus
30
+ :param lame1: lame's first parameter
31
+ :returns: [E, G, poisson's ratio, and p-wave modulus]
32
+ :rtype: list of 4 floats
33
+ """
34
+ E = (9*K * (K-lame1) ) / (3*K - lame1)
35
+ G = (3 * (K-lame1) ) / 2
36
+ pr = lame1 / (3*K - lame1)
37
+ M = 3*K - 2*lame1
38
+ return [E, G, pr, M]
39
+
40
+
41
+ def get_constants_from_bulk_and_shear(K, G):
42
+ """
43
+ Given Bulk modulus (K) and shear modulus (G), what are the other elastic constants?
44
+
45
+ :param K: bulk modulus
46
+ :param G: shear modulus
47
+ :returns: [E, lame1, poisson's ratio, and p-wave modulus]
48
+ :rtype: list of 4 floats
49
+ """
50
+ E = (9*K*G) / (3*K + G)
51
+ lame1 = K - (2*G / 3)
52
+ pr = (3*K - 2*G) / (2*(3*K+G))
53
+ M = K + (4*G / 3)
54
+ return [E, lame1, pr, M]
55
+
56
+
57
+ def get_constants_from_bulk_and_pr(K, nu):
58
+ """
59
+ Given Bulk modulus (K) and poisson's ratio (nu), what are the other elastic constants?
60
+
61
+ :param K: bulk modulus
62
+ :param nu: poisson's ratio
63
+ :returns: [E, G, lame1, and p-wave modulus]
64
+ :rtype: list of 4 floats
65
+ """
66
+ E = 3*K*(1-2*nu)
67
+ lame1 = (3*K*nu)/(1+nu)
68
+ G = (3*K*(1-2*nu))/(2*(1+nu))
69
+ M = (3*K*(1-nu))/(1+nu)
70
+ return [E, lame1, G, M]
71
+
72
+
73
+ def get_constants_from_bulk_and_pwave(K, M):
74
+ """
75
+ Given Bulk modulus (K) and P-wave modulus (M), what are the other elastic constants?
76
+
77
+ :param K: bulk modulus
78
+ :param M: p-wave modulus
79
+ :returns: [E, G, lame1, and poisson's ratio]
80
+ :rtype: list of 4 floats
81
+ """
82
+ E = (9*K*(M-K))/(3*K + M)
83
+ lame1 = (3*K - M) / 2
84
+ G = (3 * (M-K)) / 4
85
+ pr = (3*K - M)/(3*K + M)
86
+ return [E, lame1, G, pr]
87
+
88
+
89
+ def get_constants_from_youngs_and_lame1(E, lame1):
90
+ """
91
+ Given Young's modulus (E) and lame1 (lambda), what are the other elastic constants?
92
+
93
+ :param E: Young's modulus
94
+ :param lame1: lame's first parameter
95
+ :returns: [K, G, poisson's ratio, and p-wave modulus]
96
+ :rtype: list of 4 floats
97
+ """
98
+ R = np.sqrt(E*E + 9*lame1*lame1 + 2*E*lame1)
99
+ K = (E + 3*lame1 + R) / 6
100
+ G = (E - 3*lame1 + R) / 4
101
+ pr = (2*lame1) / (E+lame1+R)
102
+ M = (E-lame1+R) / 2
103
+ return [K, G, pr, M]
104
+
105
+
106
+ def get_constants_from_youngs_and_shear(E, G):
107
+ """
108
+ Given Young's modulus (E) and shear modulus (G), what are the other elastic constants?
109
+
110
+ :param E: Young's modulus
111
+ :param G: shear modulus
112
+ :returns: [K, lame1, poisson's ratio, and p-wave modulus]
113
+ :rtype: list of 4 floats
114
+ """
115
+ K = (E*G) / (3*(3*G - E))
116
+ lame1 = (G*(E-2*G)) / (3*G - E)
117
+ pr = (E/(2*G)) - 1
118
+ M = (G*(4*G - E)) / (3*G - E)
119
+ return [K, lame1, pr, M]
120
+
121
+
122
+ def get_constants_from_youngs_and_nu(E, nu):
123
+ """
124
+ Given Young's modulus (E) and poisson's ratio (nu), what are the other elastic constants?
125
+
126
+ :param E: Young's modulus
127
+ :param nu: poisson's ratio
128
+ :returns: [K, lame1, G, and p-wave modulus]
129
+ :rtype: list of 4 floats
130
+ """
131
+ K = E / (3*(1-2*nu))
132
+ lame1 = (E*nu) / ((1+nu) * (1-2*nu))
133
+ G = E / (2*(1+nu))
134
+ M = (E*(1-nu)) / ((1+nu)*(1-2*nu))
135
+ return [K, lame1, G, M]
136
+
137
+
138
+ def get_constants_from_lame1_and_shear(lame1, G):
139
+ """
140
+ Given lame1 (lambda) and shear modulus (G), what are the other elastic constants?
141
+
142
+ :param lame1: lame's first parameter
143
+ :param G: shear modulus
144
+ :returns: [K, E, poisson's ratio, and p-wave modulus]
145
+ :rtype: list of 4 floats
146
+ """
147
+ K = lame1 + (2*G)/3
148
+ E = (G * (3*lame1 + 2*G)) / (lame1 + G)
149
+ pr = lame1 / (2 * (lame1 + G))
150
+ M = lame1 + 2*G
151
+ return [K, E, pr, M]
152
+
153
+
154
+ def get_constants_from_lame1_and_nu(lame1, nu):
155
+ """
156
+ Given lame1 (lambda) and poisson's ratio (nu), what are the other elastic constants?
157
+
158
+ :param lame1: lame's first parameter
159
+ :param nu: poisson's ratio
160
+ :returns: [K, E, G, and p-wave modulus]
161
+ :rtype: list of 4 floats
162
+ """
163
+ K = (lame1 * (1+nu)) / (3*nu)
164
+ E = (lame1 * (1+nu) * (1-2*nu)) / nu
165
+ G = (lame1 * (1-2*nu)) / (2*nu)
166
+ M = (lame1 * (1-nu)) / nu
167
+ return [K, E, G, M]
168
+
169
+
170
+ def get_constants_from_lame1_and_pwave(lame1, M):
171
+ """
172
+ Given lame1 (lambda) and P-wave modulus (M), what are the other elastic constants?
173
+
174
+ :param lame1: lame's first parameter
175
+ :param M: p-wave modulus
176
+ :returns: [K, E, G, and poisson's ratio]
177
+ :rtype: list of 4 floats
178
+ """
179
+ K = (M+2*lame1) / 3
180
+ E = (M-lame1)*(M+2*lame1) / (M+lame1)
181
+ G = (M-lame1) / 2
182
+ pr = lame1 / (M+lame1)
183
+ return [K, E, G, pr]
184
+
185
+
186
+ def get_constants_from_shear_and_nu(G, nu):
187
+ """
188
+ Given shear modulus (G) and poisson's ratio (nu), what are the other elastic constants?
189
+
190
+ :param G: shear modulus
191
+ :param nu: poisson's ratio
192
+ :returns: [K, E, lame1, and p-wave modulus]
193
+ :rtype: list of 4 floats
194
+ """
195
+ K = (2*G*(1+nu)) / (3 * (1-2*nu))
196
+ E = 2*G*(1+nu)
197
+ lame1 = (2*G*nu) / (1-2*nu)
198
+ M = (2*G*(1-nu)) / (1-2*nu)
199
+ return [K, E, lame1, M]
200
+
201
+
202
+ def get_constants_from_shear_and_pwave(G, M):
203
+ """
204
+ Given shear modulus (G) and p-wave modulus (M), what are the other elastic constants?
205
+
206
+ :param G: shear modulus
207
+ :param M: p-wave modulus
208
+ :returns: [K, E, lame1, and pr]
209
+ :rtype: list of 4 floats
210
+ """
211
+ K = M - (4*G)/3
212
+ E = (G * (3*M - 4*G)) / (M-G)
213
+ lame1 = M - 2*G
214
+ pr = (M-2*G) / (2*M - 2*G)
215
+ return [K, E, lame1, pr]
216
+
217
+
218
+ def get_constants_from_nu_and_pwave(nu, M):
219
+ """
220
+ Given shear modulus (G) and p-wave modulus (M), what are the other elastic constants?
221
+
222
+ :param nu: poisson's ratio
223
+ :param M: p-wave modulus
224
+ :returns: [K, E, G, and lame1]
225
+ :rtype: list of 4 floats
226
+ """
227
+ K = (M * (1+nu)) / (3 * (1-nu))
228
+ E = (M * (1+nu) * (1-2*nu)) / (1-nu)
229
+ lame1 = (M * nu) / (1-nu)
230
+ G = (M * (1-2*nu) ) / (2 * (1-nu))
231
+ return [K, E, G, lame1]
Binary file
File without changes
@@ -0,0 +1,74 @@
1
+ # Testing code
2
+
3
+ import numpy as np
4
+ import unittest
5
+ from .. import fault_vector_functions, xyz2llh
6
+
7
+
8
+ class Tests(unittest.TestCase):
9
+
10
+ def test_strike(self):
11
+ strike = fault_vector_functions.get_strike(deltax=1.0, deltay=0.0)
12
+ self.assertEqual(strike, 90)
13
+ strike = fault_vector_functions.get_strike(deltax=-1.0, deltay=0.0)
14
+ self.assertEqual(strike, 270)
15
+ strike = fault_vector_functions.get_strike(deltax=0.0, deltay=-1.0)
16
+ self.assertEqual(strike, 180)
17
+ angle = -160
18
+ strike = fault_vector_functions.get_strike(deltax=np.cos(np.deg2rad(angle)), deltay=np.sin(np.deg2rad(angle)))
19
+ self.assertEqual(strike, 250)
20
+ return
21
+
22
+ def test_rake(self):
23
+ rake = fault_vector_functions.get_rake(rtlat_strike_slip=-1.0, dip_slip=0.5)
24
+ self.assertAlmostEqual(rake, 26.5650511770779)
25
+ return
26
+
27
+ def test_plane_normal(self):
28
+ plane_normal = fault_vector_functions.get_plane_normal(strike=0, dip=0)
29
+ self.assertTrue(np.allclose(plane_normal, [0, 0, 1])) # the calculated answer
30
+ plane_normal = fault_vector_functions.get_plane_normal(strike=90, dip=89.99)
31
+ self.assertTrue(np.allclose(plane_normal, [0, -1, 0.0001745329])) # the calculated answer
32
+ plane_normal = fault_vector_functions.get_plane_normal(strike=270, dip=89.99)
33
+ self.assertTrue(np.allclose(plane_normal, [0, 1, 0.0001745329]))
34
+ plane_normal = fault_vector_functions.get_plane_normal(strike=180, dip=1)
35
+ self.assertTrue(np.allclose(plane_normal, [-0.0174524064372835, 0, 0.999847695156391]))
36
+ return
37
+
38
+ def test_llh_xyz_conversion(self):
39
+ """ Testing conversion between xyz and llh coordinates """
40
+ print("Testing llh/enu/xyz conversion math")
41
+ llh_point = np.array([[-121.98765, 37.12345, 0],
42
+ [-121.98765, 38.12345, 0], ])
43
+ xyz = xyz2llh.llh2xyz(llh_point)
44
+ llh_back = xyz2llh.xyz2llh(xyz)
45
+ self.assertTrue(np.allclose(llh_point, llh_back, atol=1e-6))
46
+
47
+ # Testing the xyz to llh conversion on values from a AC11 pos file from PBO GPS data.
48
+ xyz_point = np.array([[-2571637.61354, -1586307.97196, 5599086.71297], ])
49
+ AC11_location = np.array([[211.6682527307-360, 61.8070788863, 790.83844], ])
50
+ llh_point = xyz2llh.xyz2llh(xyz_point)
51
+ self.assertTrue(np.allclose(llh_point, AC11_location))
52
+ return
53
+
54
+ def test_enu_conversion(self):
55
+ # Testing enu local conversion for station AC11 PBO GPS data
56
+ # Functions can use LLH or XYZ origin
57
+ reference_xyz = np.array([-2571637.71108, -1586307.90018, 5599086.75442]) # 1d array from pos file
58
+ reference_llh = np.array([211.6682506012 - 360, 61.8070787035], ) # llh reference position
59
+ xyz_obs_2005 = np.array([[-2571637.61354, -1586307.97196, 5599086.71297], ]) # xyz position on 20050721
60
+ enu_from_pos_file = np.array([[0.11200, 0.02035, -0.05795], ]) # enu position on 20050721
61
+ e_enu, _ = xyz2llh.xyz2enu(np.subtract(xyz_obs_2005, reference_xyz), reference_llh, dcov=None)
62
+ self.assertTrue(np.allclose(e_enu, enu_from_pos_file, atol=1e-3))
63
+
64
+ # Trying the enu to xyz coordinates
65
+ e_xyz, _ = xyz2llh.enu2xyz(enu_from_pos_file, reference_xyz, dcov=None)
66
+ self.assertTrue(np.allclose(np.add(e_xyz, reference_xyz), xyz_obs_2005, atol=1e-3))
67
+ # Feel-good code: check out the print statements!
68
+ print("pos file enu vs computed enu: ", enu_from_pos_file, e_enu)
69
+ print("pos_xyz_obs vs computed xyz_obs: ", xyz_obs_2005, np.add(e_xyz, reference_xyz))
70
+ return
71
+
72
+
73
+ if __name__ == "__main__":
74
+ unittest.main()
@@ -0,0 +1,33 @@
1
+ # Testing code
2
+
3
+ import unittest
4
+ import numpy as np
5
+ from .. import euler_pole
6
+
7
+
8
+ def flush_euler_vector_to_euler_pole(euler_pole_start):
9
+ """ Convert an euler pole to an euler vector and back. """
10
+ euler_vector = euler_pole.euler_pole_to_euler_vector(euler_pole_start)
11
+ euler_pole_returned = euler_pole.euler_vector_to_euler_pole(euler_vector)
12
+ return euler_pole_returned
13
+
14
+
15
+ class Tests(unittest.TestCase):
16
+
17
+ def test_euler_vector_and_pole(self):
18
+ """Test the math converting euler poles and euler vectors"""
19
+ euler_pole_start = [-120, 40, 0.22]
20
+ euler_pole_returned = flush_euler_vector_to_euler_pole(euler_pole_start)
21
+ self.assertTrue(np.allclose(list(euler_pole_start), list(euler_pole_returned)))
22
+ euler_pole_start = [-120, 40, -0.22]
23
+ euler_pole_returned = flush_euler_vector_to_euler_pole(euler_pole_start)
24
+ euler_pole_returned = euler_pole.get_opposite_ep(euler_pole_returned)
25
+ self.assertTrue(np.allclose(list(euler_pole_start), list(euler_pole_returned)))
26
+ euler_pole_start = [-120, -40, -0.22]
27
+ euler_pole_returned = flush_euler_vector_to_euler_pole(euler_pole_start)
28
+ euler_pole_returned = euler_pole.get_opposite_ep(euler_pole_returned)
29
+ self.assertTrue(np.allclose(list(euler_pole_start), list(euler_pole_returned)))
30
+
31
+
32
+ if __name__ == "__main__":
33
+ unittest.main()
@@ -0,0 +1,36 @@
1
+ # Testing code
2
+
3
+ import numpy as np
4
+ import unittest
5
+ from .. import insar_vector_functions
6
+
7
+
8
+ class Tests(unittest.TestCase):
9
+
10
+ def test_lkv_conversion(self):
11
+ """ Test that look vectors are converted to azimuth/incidence, for scalar and numpy array operation"""
12
+ [lkv_e, lkv_n, lkv_u] = insar_vector_functions.flight_incidence_angles2look_vector(190, 30)
13
+ [out_flight, out_inc] = insar_vector_functions.look_vector2flight_incidence_angles(lkv_e, lkv_n, lkv_u)
14
+ self.assertAlmostEqual(190, out_flight)
15
+ self.assertAlmostEqual(30, out_inc)
16
+
17
+ incidence_grd = np.multiply(37, np.ones((10, 10))) # in degrees
18
+ azimuth_grd = np.multiply(190, np.ones((10, 10))) # in degrees
19
+ e_grd, n_grd, u_grd = insar_vector_functions.flight_incidence_angles2look_vector(azimuth_grd, incidence_grd)
20
+ azimuth_ret, incidence_ret = insar_vector_functions.look_vector2flight_incidence_angles(e_grd, n_grd, u_grd)
21
+ np.testing.assert_allclose(azimuth_grd, azimuth_ret)
22
+ np.testing.assert_allclose(incidence_grd, incidence_ret)
23
+ return
24
+
25
+ def test_proj_into_vertical_no_horizontal(self):
26
+ # LKV 45 degree test case:
27
+ semivert = insar_vector_functions.proj_los_into_vertical_no_horiz(1, [0.7, 0, 0.7])
28
+ self.assertAlmostEqual(semivert, 1.41421356)
29
+ # LKV vertical test case:
30
+ semivert = insar_vector_functions.proj_los_into_vertical_no_horiz(1, [0, 0, 1])
31
+ self.assertAlmostEqual(semivert, 1.0)
32
+ return
33
+
34
+
35
+ if __name__ == "__main__":
36
+ unittest.main()