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.
- tectonic_utils/.DS_Store +0 -0
- tectonic_utils/__init__.py +3 -0
- tectonic_utils/cover_picture.png +0 -0
- tectonic_utils/geodesy/.DS_Store +0 -0
- tectonic_utils/geodesy/.ruff_cache/.gitignore +1 -0
- tectonic_utils/geodesy/.ruff_cache/0.1.5/15663111236935520357 +0 -0
- tectonic_utils/geodesy/.ruff_cache/CACHEDIR.TAG +1 -0
- tectonic_utils/geodesy/__init__.py +0 -0
- tectonic_utils/geodesy/datums.py +156 -0
- tectonic_utils/geodesy/euler_pole.py +170 -0
- tectonic_utils/geodesy/fault_vector_functions.py +383 -0
- tectonic_utils/geodesy/haversine.py +193 -0
- tectonic_utils/geodesy/insar_vector_functions.py +285 -0
- tectonic_utils/geodesy/linear_elastic.py +231 -0
- tectonic_utils/geodesy/test/.DS_Store +0 -0
- tectonic_utils/geodesy/test/__init__.py +0 -0
- tectonic_utils/geodesy/test/test_conversion_functions.py +74 -0
- tectonic_utils/geodesy/test/test_euler_poles.py +33 -0
- tectonic_utils/geodesy/test/test_insar_vector_functions.py +36 -0
- tectonic_utils/geodesy/utilities.py +47 -0
- tectonic_utils/geodesy/xyz2llh.py +220 -0
- tectonic_utils/read_write/.DS_Store +0 -0
- tectonic_utils/read_write/.ruff_cache/.gitignore +1 -0
- tectonic_utils/read_write/.ruff_cache/0.1.5/680373307893520726 +0 -0
- tectonic_utils/read_write/.ruff_cache/CACHEDIR.TAG +1 -0
- tectonic_utils/read_write/__init__.py +0 -0
- tectonic_utils/read_write/general_io.py +55 -0
- tectonic_utils/read_write/netcdf_read_write.py +382 -0
- tectonic_utils/read_write/read_kml.py +68 -0
- tectonic_utils/read_write/test/.DS_Store +0 -0
- tectonic_utils/read_write/test/__init__.py +0 -0
- tectonic_utils/read_write/test/example_grd.grd +0 -0
- tectonic_utils/read_write/test/test_conversion_functions.py +40 -0
- tectonic_utils/read_write/test/written_example.grd +0 -0
- tectonic_utils/seismo/.DS_Store +0 -0
- tectonic_utils/seismo/.ruff_cache/.gitignore +1 -0
- tectonic_utils/seismo/.ruff_cache/0.1.5/12911000862714636977 +0 -0
- tectonic_utils/seismo/.ruff_cache/CACHEDIR.TAG +1 -0
- tectonic_utils/seismo/MT_calculations.py +132 -0
- tectonic_utils/seismo/__init__.py +0 -0
- tectonic_utils/seismo/moment_calculations.py +44 -0
- tectonic_utils/seismo/second_focal_plane.py +138 -0
- tectonic_utils/seismo/test/.DS_Store +0 -0
- tectonic_utils/seismo/test/__init__.py +0 -0
- tectonic_utils/seismo/test/test_WC.py +19 -0
- tectonic_utils/seismo/test/test_second_focal_plane.py +16 -0
- tectonic_utils/seismo/wells_and_coppersmith.py +167 -0
- tectonic_utils-0.1.2.dist-info/LICENSE.md +21 -0
- tectonic_utils-0.1.2.dist-info/METADATA +82 -0
- tectonic_utils-0.1.2.dist-info/RECORD +51 -0
- 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()
|