cfs-python 0.1.0__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.
- app_panel.py +1058 -0
- cfs_lib/__init__.py +0 -0
- cfs_lib/coulomb_math.py +142 -0
- cfs_lib/io_parser.py +165 -0
- cfs_lib/main.py +173 -0
- cfs_lib/okada_math.py +652 -0
- cfs_lib/okada_wrapper.py +148 -0
- cfs_python-0.1.0.dist-info/METADATA +51 -0
- cfs_python-0.1.0.dist-info/RECORD +11 -0
- cfs_python-0.1.0.dist-info/WHEEL +5 -0
- cfs_python-0.1.0.dist-info/top_level.txt +2 -0
cfs_lib/__init__.py
ADDED
|
File without changes
|
cfs_lib/coulomb_math.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def calc_coulomb(strike_m, dip_m, rake_m, friction_m, ss):
|
|
4
|
+
"""
|
|
5
|
+
Calculates shear, normal, and Coulomb stresses on a given fault.
|
|
6
|
+
strike_m, dip_m, rake_m, friction_m: 1D numpy arrays of shape (n,)
|
|
7
|
+
ss: 2D numpy array of shape (6, n) [SXX, SYY, SZZ, SYZ, SXZ, SXY]
|
|
8
|
+
Returns shear, normal, coulomb (each shape (n,))
|
|
9
|
+
"""
|
|
10
|
+
n = len(strike_m)
|
|
11
|
+
friction = float(friction_m[0]) if isinstance(friction_m, np.ndarray) else friction_m
|
|
12
|
+
|
|
13
|
+
# adjustment for coordinate system from Aki & Richards
|
|
14
|
+
c1 = strike_m >= 180.0
|
|
15
|
+
c2 = strike_m < 180.0
|
|
16
|
+
|
|
17
|
+
strike = (strike_m - 180.0) * c1 + strike_m * c2
|
|
18
|
+
dip = -1.0 * dip_m * c1 + dip_m * c2
|
|
19
|
+
rake_m = rake_m - 90.0
|
|
20
|
+
|
|
21
|
+
c1 = rake_m <= -180.0
|
|
22
|
+
c2 = rake_m > -180.0
|
|
23
|
+
rake = (360.0 + rake_m) * c1 + rake_m * c2
|
|
24
|
+
|
|
25
|
+
strike = np.deg2rad(strike)
|
|
26
|
+
dip = np.deg2rad(dip)
|
|
27
|
+
rake = np.deg2rad(rake)
|
|
28
|
+
|
|
29
|
+
# Rake rotation
|
|
30
|
+
rsc = -rake
|
|
31
|
+
mtran = np.zeros((3, 3, n), dtype=np.float64)
|
|
32
|
+
# create xrotate matrix for each n
|
|
33
|
+
# rr = makehgtform('xrotate', rsc); in python:
|
|
34
|
+
# [1, 0, 0; 0, cos(a), -sin(a); 0, sin(a), cos(a)]
|
|
35
|
+
for i in range(n):
|
|
36
|
+
c_a = np.cos(rsc[i])
|
|
37
|
+
s_a = np.sin(rsc[i])
|
|
38
|
+
mtran[:, :, i] = np.array([
|
|
39
|
+
[1.0, 0.0, 0.0],
|
|
40
|
+
[0.0, c_a, -s_a],
|
|
41
|
+
[0.0, s_a, c_a]
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
ver = np.pi / 2.0
|
|
45
|
+
|
|
46
|
+
c1 = strike >= 0.0
|
|
47
|
+
c2 = strike < 0.0
|
|
48
|
+
c3 = strike <= ver
|
|
49
|
+
c4 = strike > ver
|
|
50
|
+
|
|
51
|
+
c24 = c2 | c4
|
|
52
|
+
|
|
53
|
+
d1 = dip >= 0.0
|
|
54
|
+
d2 = dip < 0.0
|
|
55
|
+
|
|
56
|
+
xbeta = -1.0 * strike * d1 + (np.pi - strike) * d2
|
|
57
|
+
ybeta = (np.pi - strike) * d1 + -1.0 * strike * d2
|
|
58
|
+
zbeta = (ver - strike) * d1 + (-1.0 * ver - strike) * d2 * c1 * c3 + (np.pi + ver - strike) * d2 * c24
|
|
59
|
+
|
|
60
|
+
xdel = ver - np.abs(dip)
|
|
61
|
+
ydel = np.abs(dip)
|
|
62
|
+
zdel = np.zeros(n)
|
|
63
|
+
|
|
64
|
+
xl = np.cos(xdel) * np.cos(xbeta)
|
|
65
|
+
xm = np.cos(xdel) * np.sin(xbeta)
|
|
66
|
+
xn = np.sin(xdel)
|
|
67
|
+
yl = np.cos(ydel) * np.cos(ybeta)
|
|
68
|
+
ym = np.cos(ydel) * np.sin(ybeta)
|
|
69
|
+
yn = np.sin(ydel)
|
|
70
|
+
zl = np.cos(zdel) * np.cos(zbeta)
|
|
71
|
+
zm = np.cos(zdel) * np.sin(zbeta)
|
|
72
|
+
zn = np.sin(zdel)
|
|
73
|
+
|
|
74
|
+
t = np.zeros((6, 6, n), dtype=np.float64)
|
|
75
|
+
|
|
76
|
+
t[0, 0, :] = xl * xl
|
|
77
|
+
t[0, 1, :] = xm * xm
|
|
78
|
+
t[0, 2, :] = xn * xn
|
|
79
|
+
t[0, 3, :] = 2.0 * xm * xn
|
|
80
|
+
t[0, 4, :] = 2.0 * xn * xl
|
|
81
|
+
t[0, 5, :] = 2.0 * xl * xm
|
|
82
|
+
|
|
83
|
+
t[1, 0, :] = yl * yl
|
|
84
|
+
t[1, 1, :] = ym * ym
|
|
85
|
+
t[1, 2, :] = yn * yn
|
|
86
|
+
t[1, 3, :] = 2.0 * ym * yn
|
|
87
|
+
t[1, 4, :] = 2.0 * yn * yl
|
|
88
|
+
t[1, 5, :] = 2.0 * yl * ym
|
|
89
|
+
|
|
90
|
+
t[2, 0, :] = zl * zl
|
|
91
|
+
t[2, 1, :] = zm * zm
|
|
92
|
+
t[2, 2, :] = zn * zn
|
|
93
|
+
t[2, 3, :] = 2.0 * zm * zn
|
|
94
|
+
t[2, 4, :] = 2.0 * zn * zl
|
|
95
|
+
t[2, 5, :] = 2.0 * zl * zm
|
|
96
|
+
|
|
97
|
+
t[3, 0, :] = yl * zl
|
|
98
|
+
t[3, 1, :] = ym * zm
|
|
99
|
+
t[3, 2, :] = yn * zn
|
|
100
|
+
t[3, 3, :] = ym * zn + zm * yn
|
|
101
|
+
t[3, 4, :] = yn * zl + zn * yl
|
|
102
|
+
t[3, 5, :] = yl * zm + zl * ym
|
|
103
|
+
|
|
104
|
+
t[4, 0, :] = zl * xl
|
|
105
|
+
t[4, 1, :] = zm * xm
|
|
106
|
+
t[4, 2, :] = zn * xn
|
|
107
|
+
t[4, 3, :] = xm * zn + zm * xn
|
|
108
|
+
t[4, 4, :] = xn * zl + zn * xl
|
|
109
|
+
t[4, 5, :] = xl * zm + zl * xm
|
|
110
|
+
|
|
111
|
+
t[5, 0, :] = xl * yl
|
|
112
|
+
t[5, 1, :] = xm * ym
|
|
113
|
+
t[5, 2, :] = xn * yn
|
|
114
|
+
t[5, 3, :] = xm * yn + ym * xn
|
|
115
|
+
t[5, 4, :] = xn * yl + yn * xl
|
|
116
|
+
t[5, 5, :] = xl * ym + yl * xm
|
|
117
|
+
|
|
118
|
+
sn = np.zeros((6, n), dtype=np.float64)
|
|
119
|
+
sn9 = np.zeros((3, 3, n), dtype=np.float64)
|
|
120
|
+
|
|
121
|
+
for k in range(n):
|
|
122
|
+
sn[:, k] = np.dot(t[:, :, k], ss[:, k])
|
|
123
|
+
|
|
124
|
+
sn9[0, 0, k] = sn[0, k]
|
|
125
|
+
sn9[0, 1, k] = sn[5, k]
|
|
126
|
+
sn9[0, 2, k] = sn[4, k]
|
|
127
|
+
|
|
128
|
+
sn9[1, 0, k] = sn[5, k]
|
|
129
|
+
sn9[1, 1, k] = sn[1, k]
|
|
130
|
+
sn9[1, 2, k] = sn[3, k]
|
|
131
|
+
|
|
132
|
+
sn9[2, 0, k] = sn[4, k]
|
|
133
|
+
sn9[2, 1, k] = sn[3, k]
|
|
134
|
+
sn9[2, 2, k] = sn[2, k]
|
|
135
|
+
|
|
136
|
+
sn9[:, :, k] = np.dot(sn9[:, :, k], mtran[:, :, k])
|
|
137
|
+
|
|
138
|
+
shear = sn9[0, 1, :]
|
|
139
|
+
normal = sn9[0, 0, :]
|
|
140
|
+
coulomb = shear + friction * normal
|
|
141
|
+
|
|
142
|
+
return shear, normal, coulomb
|
cfs_lib/io_parser.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
def open_input_file_cui(filename):
|
|
5
|
+
"""
|
|
6
|
+
Parses a Coulomb 3.3 format text file.
|
|
7
|
+
Returns: xvec, yvec, z, el, kode, pois, young, cdepth, fric, rstress
|
|
8
|
+
"""
|
|
9
|
+
with open(filename, 'r', encoding='utf-8', errors='ignore') as f:
|
|
10
|
+
lines = f.readlines()
|
|
11
|
+
|
|
12
|
+
num = 0
|
|
13
|
+
pois = 0.25
|
|
14
|
+
cdepth = 7.5
|
|
15
|
+
young = 8e5
|
|
16
|
+
fric = 0.4
|
|
17
|
+
rstress = [0.0, 0.0, 0.0]
|
|
18
|
+
|
|
19
|
+
grid = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # xstart, ystart, xend, yend, xinc, yinc
|
|
20
|
+
map_info = {}
|
|
21
|
+
cross_section = {}
|
|
22
|
+
|
|
23
|
+
in_fault_elements = False
|
|
24
|
+
in_grid_params = False
|
|
25
|
+
faults = []
|
|
26
|
+
|
|
27
|
+
for i, line in enumerate(lines):
|
|
28
|
+
# We need to read PR1, YOUNG'S, FRIC. COEFFICIENT, SIGMA1-SIGMA3, Grid parameters
|
|
29
|
+
up_line = line.upper()
|
|
30
|
+
|
|
31
|
+
if "PR1=" in up_line:
|
|
32
|
+
parts = line.split()
|
|
33
|
+
try:
|
|
34
|
+
pois = float(parts[1])
|
|
35
|
+
cdepth = float(parts[5])
|
|
36
|
+
except: pass
|
|
37
|
+
|
|
38
|
+
if "YOUNG'S MODULUS" in up_line:
|
|
39
|
+
try: young = float(line.split()[0])
|
|
40
|
+
except: pass
|
|
41
|
+
|
|
42
|
+
if "FRIC. COEFFICIENT" in up_line:
|
|
43
|
+
try: fric = float(line.split()[0])
|
|
44
|
+
except: pass
|
|
45
|
+
|
|
46
|
+
if "SIGMA1-SIGMA3" in up_line:
|
|
47
|
+
floats = [float(s) for s in re.findall(r'-?\d+\.?\d*', line)]
|
|
48
|
+
if len(floats) >= 3:
|
|
49
|
+
rstress = floats[:3]
|
|
50
|
+
|
|
51
|
+
if "X-START" in up_line:
|
|
52
|
+
in_grid_params = True
|
|
53
|
+
|
|
54
|
+
if "XXX" in up_line:
|
|
55
|
+
in_fault_elements = not in_fault_elements
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
if in_fault_elements:
|
|
59
|
+
parts = line.split()
|
|
60
|
+
if len(parts) >= 11:
|
|
61
|
+
try:
|
|
62
|
+
xs, ys, xf, yf = map(float, parts[1:5])
|
|
63
|
+
kode = int(parts[5])
|
|
64
|
+
|
|
65
|
+
if "RAKE" in " ".join(lines).upper():
|
|
66
|
+
rake, netslip, dip, top, bottom = map(float, parts[6:11])
|
|
67
|
+
latslip = np.cos(np.deg2rad(rake)) * netslip * -1.0
|
|
68
|
+
dipslip = np.sin(np.deg2rad(rake)) * netslip
|
|
69
|
+
else:
|
|
70
|
+
latslip, dipslip, dip, top, bottom = map(float, parts[6:11])
|
|
71
|
+
|
|
72
|
+
faults.append([xs, ys, xf, yf, latslip, dipslip, dip, top, bottom, kode])
|
|
73
|
+
except ValueError:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# reading grid info
|
|
77
|
+
if "CROSS SECTION DEFAULT" in up_line:
|
|
78
|
+
in_grid_params = False
|
|
79
|
+
in_fault_elements = False
|
|
80
|
+
continue
|
|
81
|
+
elif "MAP INFO" in up_line:
|
|
82
|
+
in_grid_params = False
|
|
83
|
+
in_fault_elements = False
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
if in_grid_params and "=" in line:
|
|
87
|
+
parts = line.split("=")
|
|
88
|
+
if len(parts) == 2:
|
|
89
|
+
try:
|
|
90
|
+
val = float(parts[1].split()[0])
|
|
91
|
+
if "X-start" in up_line: grid[0] = val
|
|
92
|
+
elif "Y-start" in up_line: grid[1] = val
|
|
93
|
+
elif "X-finish" in up_line: grid[2] = val
|
|
94
|
+
elif "Y-finish" in up_line: grid[3] = val
|
|
95
|
+
elif "X-inc" in up_line: grid[4] = val
|
|
96
|
+
elif "Y-inc" in up_line:
|
|
97
|
+
grid[5] = val
|
|
98
|
+
in_grid_params = False
|
|
99
|
+
except:
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
# We can just look for specific keywords for map info and cross section
|
|
103
|
+
if "=" in line:
|
|
104
|
+
parts = line.split("=")
|
|
105
|
+
if len(parts) == 2:
|
|
106
|
+
try:
|
|
107
|
+
val = float(parts[1].split()[0])
|
|
108
|
+
# Cross section
|
|
109
|
+
if "START-X" in up_line and "DEFAULT" not in up_line and not in_grid_params: cross_section["start_x"] = val
|
|
110
|
+
elif "START-Y" in up_line and not in_grid_params: cross_section["start_y"] = val
|
|
111
|
+
elif "FINISH-X" in up_line and not in_grid_params: cross_section["finish_x"] = val
|
|
112
|
+
elif "FINISH-Y" in up_line and not in_grid_params: cross_section["finish_y"] = val
|
|
113
|
+
|
|
114
|
+
# Map Info
|
|
115
|
+
elif "MIN. LON" in up_line: map_info["min_lon"] = val
|
|
116
|
+
elif "MAX. LON" in up_line: map_info["max_lon"] = val
|
|
117
|
+
elif "ZERO LON" in up_line: map_info["zero_lon"] = val
|
|
118
|
+
elif "MIN. LAT" in up_line: map_info["min_lat"] = val
|
|
119
|
+
elif "MAX. LAT" in up_line: map_info["max_lat"] = val
|
|
120
|
+
elif "ZERO LAT" in up_line: map_info["zero_lat"] = val
|
|
121
|
+
except:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
if len(faults) == 0:
|
|
125
|
+
raise ValueError("No valid faults found in the input file.")
|
|
126
|
+
|
|
127
|
+
faults = np.array(faults)
|
|
128
|
+
el = faults[:, :9]
|
|
129
|
+
kode = faults[:, 9].astype(int)
|
|
130
|
+
|
|
131
|
+
# safeguard grid increments to prevent memory error
|
|
132
|
+
xin = max(grid[4], 0.001)
|
|
133
|
+
yin = max(grid[5], 0.001)
|
|
134
|
+
|
|
135
|
+
xvec = np.arange(grid[0], grid[2] + xin*0.5, xin)
|
|
136
|
+
yvec = np.arange(grid[1], grid[3] + yin*0.5, yin)
|
|
137
|
+
z = cdepth
|
|
138
|
+
|
|
139
|
+
# Default missing map info to 0.0
|
|
140
|
+
for k in ["min_lon", "max_lon", "zero_lon", "min_lat", "max_lat", "zero_lat"]:
|
|
141
|
+
if k not in map_info:
|
|
142
|
+
map_info[k] = 0.0
|
|
143
|
+
|
|
144
|
+
return xvec, yvec, z, el, kode, pois, young, cdepth, fric, rstress, map_info, cross_section
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def open_batch_file(filename):
|
|
148
|
+
with open(filename, 'r', encoding='utf-8', errors='ignore') as f:
|
|
149
|
+
lines = f.readlines()
|
|
150
|
+
|
|
151
|
+
data = []
|
|
152
|
+
for line in lines[2:]:
|
|
153
|
+
parts = line.split()
|
|
154
|
+
if len(parts) >= 6:
|
|
155
|
+
try:
|
|
156
|
+
data.append([float(x) for x in parts[:6]])
|
|
157
|
+
except: pass
|
|
158
|
+
|
|
159
|
+
data = np.array(data)
|
|
160
|
+
pos = data[:, :3]
|
|
161
|
+
strike = data[:, 3]
|
|
162
|
+
dip = data[:, 4]
|
|
163
|
+
rake = data[:, 5]
|
|
164
|
+
|
|
165
|
+
return pos, strike, dip, rake
|
cfs_lib/main.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .io_parser import open_input_file_cui, open_batch_file
|
|
3
|
+
from .okada_wrapper import okada_elastic_halfspace
|
|
4
|
+
from .coulomb_math import calc_coulomb
|
|
5
|
+
|
|
6
|
+
def coulomb_cui(sourceFileName='test.dat', calcFunction='deformation', receiver='30/90/180', batchFileName='test.dat', parse_only=False, grid_params=None):
|
|
7
|
+
"""
|
|
8
|
+
Python entry point for Coulomb calculations.
|
|
9
|
+
"""
|
|
10
|
+
# Parse input file
|
|
11
|
+
try:
|
|
12
|
+
xvec, yvec, z, el, kode, pois, young, cdepth, fric, rstress = open_input_file_cui(sourceFileName)
|
|
13
|
+
except FileNotFoundError:
|
|
14
|
+
print(f"File {sourceFileName} not found.")
|
|
15
|
+
return None, None
|
|
16
|
+
|
|
17
|
+
# If explicit grid params are provided (e.g. from UI), override the file ones
|
|
18
|
+
if grid_params:
|
|
19
|
+
x_start, x_end, x_inc = grid_params['min_x'], grid_params['max_x'], grid_params['inc']
|
|
20
|
+
y_start, y_end, y_inc = grid_params['min_y'], grid_params['max_y'], grid_params['inc']
|
|
21
|
+
cdepth = grid_params['depth']
|
|
22
|
+
|
|
23
|
+
# recreate xvec, yvec
|
|
24
|
+
xvec = np.arange(x_start, x_end + x_inc, x_inc)
|
|
25
|
+
yvec = np.arange(y_start, y_end + y_inc, y_inc)
|
|
26
|
+
|
|
27
|
+
if parse_only:
|
|
28
|
+
# Just return the faults and grid params for UI preview
|
|
29
|
+
results_dict = {
|
|
30
|
+
"faults": el.tolist(),
|
|
31
|
+
"x": xvec.tolist(),
|
|
32
|
+
"y": yvec.tolist(),
|
|
33
|
+
"cdepth": cdepth
|
|
34
|
+
}
|
|
35
|
+
return "parsed", results_dict
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
if calcFunction == 'deformation':
|
|
39
|
+
print(f"Calculating deformation for {sourceFileName}...")
|
|
40
|
+
dc3d = okada_elastic_halfspace(xvec, yvec, el, young, pois, cdepth, kode)
|
|
41
|
+
fout = 'halfspace_def_out.dat'
|
|
42
|
+
with open(fout, 'w') as f:
|
|
43
|
+
f.write("x y z ux uy uz sxx syy szz syz sxz sxy\n")
|
|
44
|
+
f.write("(km) (km) (km) (m) (m) (m) (bar) (bar) (bar) (bar) (bar) (bar)\n")
|
|
45
|
+
for i in range(dc3d.shape[0]):
|
|
46
|
+
# print 1:2, 5:14 (0-based: 0, 1 and 4-13)
|
|
47
|
+
row = dc3d[i]
|
|
48
|
+
arr = [row[0], row[1]] + list(row[4:14])
|
|
49
|
+
# format string
|
|
50
|
+
fmt = "".join([f"{x:10.4f}" for x in arr])
|
|
51
|
+
f.write(fmt + " \n")
|
|
52
|
+
print(f"Done. Wrote to {fout}")
|
|
53
|
+
results_dict = {
|
|
54
|
+
"x": dc3d[:, 0].tolist(),
|
|
55
|
+
"y": dc3d[:, 1].tolist(),
|
|
56
|
+
"z": dc3d[:, 4].tolist(),
|
|
57
|
+
"ux": dc3d[:, 5].tolist(),
|
|
58
|
+
"uy": dc3d[:, 6].tolist(),
|
|
59
|
+
"uz": dc3d[:, 7].tolist(),
|
|
60
|
+
"sxx": dc3d[:, 8].tolist(),
|
|
61
|
+
"syy": dc3d[:, 9].tolist(),
|
|
62
|
+
"szz": dc3d[:, 10].tolist(),
|
|
63
|
+
"syz": dc3d[:, 11].tolist(),
|
|
64
|
+
"sxz": dc3d[:, 12].tolist(),
|
|
65
|
+
"sxy": dc3d[:, 13].tolist(),
|
|
66
|
+
"faults": el.tolist()
|
|
67
|
+
}
|
|
68
|
+
return fout, results_dict
|
|
69
|
+
|
|
70
|
+
elif calcFunction == 'coulomb':
|
|
71
|
+
print(f"Calculating coulomb for {sourceFileName} at {receiver}...")
|
|
72
|
+
dc3d = okada_elastic_halfspace(xvec, yvec, el, young, pois, cdepth, kode)
|
|
73
|
+
|
|
74
|
+
parts = receiver.split('/')
|
|
75
|
+
strike_m = float(parts[0]) * np.ones(dc3d.shape[0])
|
|
76
|
+
dip_m = float(parts[1]) * np.ones(dc3d.shape[0])
|
|
77
|
+
rake_m = float(parts[2]) * np.ones(dc3d.shape[0])
|
|
78
|
+
friction_m = fric * np.ones(dc3d.shape[0])
|
|
79
|
+
|
|
80
|
+
# passed array: ss is dc3d(:, 9:14)' -> shape (6, ncell) in MATLAB
|
|
81
|
+
# python dc3d is shape (n, 14), 8-13 is stress (sxx_n to sxy_n)
|
|
82
|
+
ss = dc3d[:, 8:14].T
|
|
83
|
+
|
|
84
|
+
shear, normal, coulomb = calc_coulomb(strike_m, dip_m, rake_m, friction_m, ss)
|
|
85
|
+
|
|
86
|
+
fout = 'coulomb_out.dat'
|
|
87
|
+
with open(fout, 'w') as f:
|
|
88
|
+
f.write("x y z strike dip rake shear normal coulomb\n")
|
|
89
|
+
f.write("(km) (km) (km) (deg) (deg) (deg) (bar) (bar) (bar)\n")
|
|
90
|
+
for i in range(dc3d.shape[0]):
|
|
91
|
+
f.write(f"{dc3d[i,0]:10.4f}{dc3d[i,1]:10.4f}{dc3d[i,4]:10.4f}")
|
|
92
|
+
f.write(f"{strike_m[i]:7.1f}{dip_m[i]:6.1f}{rake_m[i]:8.1f}")
|
|
93
|
+
f.write(f"{shear[i]:10.4f}{normal[i]:10.4f}{coulomb[i]:10.4f} \n")
|
|
94
|
+
print(f"Done. Wrote to {fout}")
|
|
95
|
+
results_dict = {
|
|
96
|
+
"x": dc3d[:, 0].tolist(),
|
|
97
|
+
"y": dc3d[:, 1].tolist(),
|
|
98
|
+
"z": dc3d[:, 4].tolist(),
|
|
99
|
+
"ux": dc3d[:, 5].tolist(),
|
|
100
|
+
"uy": dc3d[:, 6].tolist(),
|
|
101
|
+
"uz": dc3d[:, 7].tolist(),
|
|
102
|
+
"sxx": dc3d[:, 8].tolist(),
|
|
103
|
+
"syy": dc3d[:, 9].tolist(),
|
|
104
|
+
"szz": dc3d[:, 10].tolist(),
|
|
105
|
+
"syz": dc3d[:, 11].tolist(),
|
|
106
|
+
"sxz": dc3d[:, 12].tolist(),
|
|
107
|
+
"sxy": dc3d[:, 13].tolist(),
|
|
108
|
+
"shear": shear.tolist(),
|
|
109
|
+
"normal": normal.tolist(),
|
|
110
|
+
"coulomb": coulomb.tolist(),
|
|
111
|
+
"faults": el.tolist()
|
|
112
|
+
}
|
|
113
|
+
return fout, results_dict
|
|
114
|
+
|
|
115
|
+
elif calcFunction == 'batch':
|
|
116
|
+
print(f"Calculating batch from {batchFileName} using {sourceFileName}...")
|
|
117
|
+
try:
|
|
118
|
+
pos, strike_m, dip_m, rake_m = open_batch_file(batchFileName)
|
|
119
|
+
except FileNotFoundError:
|
|
120
|
+
print(f"Batch file {batchFileName} not found.")
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
x_g, y_g, z_g = pos[:, 0], pos[:, 1], pos[:, 2] # actually -z in okada
|
|
124
|
+
cdepth_i = -z_g
|
|
125
|
+
|
|
126
|
+
# call okada_elastic_halfspace with all points
|
|
127
|
+
res = okada_elastic_halfspace(x_g, y_g, el, young, pois, cdepth_i, kode)
|
|
128
|
+
dc3d = res
|
|
129
|
+
|
|
130
|
+
# res shape (n_batch, 14), ss needed shape (6, n_batch) -> 8:14 transposed
|
|
131
|
+
ss = res[:, 8:14].T
|
|
132
|
+
|
|
133
|
+
s, n_s, c = calc_coulomb(strike_m, dip_m, rake_m, np.full(pos.shape[0], fric), ss)
|
|
134
|
+
shear = s
|
|
135
|
+
normal = n_s
|
|
136
|
+
coulomb = c
|
|
137
|
+
|
|
138
|
+
fout = 'coulomb_out.dat'
|
|
139
|
+
with open(fout, 'w') as f:
|
|
140
|
+
f.write("x y z strike dip rake shear normal coulomb\n")
|
|
141
|
+
f.write("(km) (km) (km) (deg) (deg) (deg) (bar) (bar) (bar)\n")
|
|
142
|
+
for i in range(dc3d.shape[0]):
|
|
143
|
+
f.write(f"{dc3d[i,0]:10.4f}{dc3d[i,1]:10.4f}{dc3d[i,4]:10.4f}")
|
|
144
|
+
f.write(f"{strike_m[i]:7.1f}{dip_m[i]:6.1f}{rake_m[i]:8.1f}")
|
|
145
|
+
f.write(f"{shear[i]:10.4f}{normal[i]:10.4f}{coulomb[i]:10.4f} \n")
|
|
146
|
+
print(f"Done. Wrote to {fout}")
|
|
147
|
+
results_dict = {
|
|
148
|
+
"x": dc3d[:, 0].tolist(),
|
|
149
|
+
"y": dc3d[:, 1].tolist(),
|
|
150
|
+
"z": dc3d[:, 4].tolist(),
|
|
151
|
+
"ux": dc3d[:, 5].tolist(),
|
|
152
|
+
"uy": dc3d[:, 6].tolist(),
|
|
153
|
+
"uz": dc3d[:, 7].tolist(),
|
|
154
|
+
"sxx": dc3d[:, 8].tolist(),
|
|
155
|
+
"syy": dc3d[:, 9].tolist(),
|
|
156
|
+
"szz": dc3d[:, 10].tolist(),
|
|
157
|
+
"syz": dc3d[:, 11].tolist(),
|
|
158
|
+
"sxz": dc3d[:, 12].tolist(),
|
|
159
|
+
"sxy": dc3d[:, 13].tolist(),
|
|
160
|
+
"shear": shear.tolist(),
|
|
161
|
+
"normal": normal.tolist(),
|
|
162
|
+
"coulomb": coulomb.tolist(),
|
|
163
|
+
"faults": el.tolist()
|
|
164
|
+
}
|
|
165
|
+
return fout, results_dict
|
|
166
|
+
else:
|
|
167
|
+
print("Invalid calcFunction")
|
|
168
|
+
return None, None
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
import sys
|
|
172
|
+
# test defaults
|
|
173
|
+
coulomb_cui()
|