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.
@@ -0,0 +1,148 @@
1
+ import numpy as np
2
+ from .okada_math import coord_conversion, tensor_trans, okada_dc3d, okada_dc3d0
3
+
4
+ def okada_elastic_halfspace(xgrid, ygrid, element, young, pois, calcdepth, kode):
5
+ """
6
+ Python equivalent of okada_elastic_halfspace.m
7
+ xgrid, ygrid: 1D numpy arrays of grid coordinates
8
+ element: 2D numpy array of fault elements. Shape (num_faults, M)
9
+ (el: xs, ys, xf, yf, latslip, dipslip, dip, top, bottom)
10
+ young: Young's modulus
11
+ pois: Poisson's ratio
12
+ calcdepth: Calculation depth (km, positive)
13
+ kode: array/list of calculation types (e.g., 100 for rectangular)
14
+ """
15
+ alpha = 1.0 / (2.0 * (1.0 - pois))
16
+
17
+ if np.isscalar(xgrid) or xgrid.size == 1:
18
+ ncell = 1
19
+ xgrid = np.array([xgrid]).flatten()
20
+ ygrid = np.array([ygrid]).flatten()
21
+ else:
22
+ # Check if xgrid and ygrid are 1D arrays creating a meshgrid,
23
+ # or if they are already parallel arrays (from batch)?
24
+ # Let's assume if they are exactly the same size, they could be a meshgrid OR a 1D parallel list.
25
+ # Wait, if it's a batch file, xgrid, ygrid, calcdepth are parallel 1D lists.
26
+ # But for deformation mesh grids, xv, yv = np.meshgrid(xgrid, ygrid) creates len(x)*len(y).
27
+ pass
28
+
29
+ # Better logic: if calcdepth is an array of same size as xgrid, we use parallel 1D computation.
30
+ is_parallel_1d = False
31
+ if isinstance(calcdepth, np.ndarray) and calcdepth.shape == xgrid.shape and xgrid.ndim == 1:
32
+ is_parallel_1d = True
33
+
34
+ if is_parallel_1d:
35
+ ncell = len(xgrid)
36
+ xycoord = np.zeros((ncell, 2), dtype=np.float64)
37
+ xycoord[:, 0] = xgrid
38
+ xycoord[:, 1] = ygrid
39
+ zd = calcdepth * (-1.0)
40
+ else:
41
+ ncell = len(xgrid) * len(ygrid) if not (np.isscalar(xgrid) or xgrid.size == 1) else 1
42
+ xycoord = np.zeros((ncell, 2), dtype=np.float64)
43
+ xv, yv = np.meshgrid(xgrid, ygrid, indexing='ij') if ncell > 1 else (xgrid, ygrid)
44
+ if ncell > 1:
45
+ xycoord[:, 0] = xv.flatten()
46
+ xycoord[:, 1] = yv.flatten()
47
+ else:
48
+ xycoord[:, 0] = xgrid
49
+ xycoord[:, 1] = ygrid
50
+ zd = np.full(ncell, calcdepth * (-1.0), dtype=np.float64)
51
+
52
+ dc3d_out = np.zeros((ncell, 14), dtype=np.float64)
53
+
54
+ for i in range(element.shape[0]):
55
+ depth = (element[i, 7] + element[i, 8]) / 2.0 # depth is positive (top+bottom)/2
56
+ c1, c2, c3, c4 = coord_conversion(
57
+ xycoord[:, 0], xycoord[:, 1],
58
+ element[i, 0], element[i, 1],
59
+ element[i, 2], element[i, 3],
60
+ element[i, 7], element[i, 8],
61
+ element[i, 6]
62
+ )
63
+
64
+ aa = np.full(ncell, alpha, dtype=np.float64)
65
+ zz = zd # already array of length ncell
66
+ dp = np.full(ncell, depth, dtype=np.float64)
67
+ e7 = np.full(ncell, element[i, 6], dtype=np.float64)
68
+ x = c1.astype(np.float64)
69
+ y = c2.astype(np.float64)
70
+ al = c3.astype(np.float64)
71
+
72
+ # Determine kode for this element
73
+ kd = kode[i] if isinstance(kode, (list, np.ndarray)) else kode
74
+
75
+ if kd == 400:
76
+ aw = np.full(ncell, -element[i, 4], dtype=np.float64)
77
+ e5 = np.full(ncell, element[i, 5], dtype=np.float64)
78
+ e6 = np.zeros(ncell, dtype=np.float64)
79
+ zr = np.zeros(ncell, dtype=np.float64)
80
+
81
+ ux, uy, uz, uxx, uyx, uzx, uxy, uyy, uzy, uxz, uyz, uzz, iret = okada_dc3d0(
82
+ aa[0], x, y, zz, dp, e7, aw, e5, e6, zr
83
+ )
84
+ elif kd == 100:
85
+ aw = c4.astype(np.float64)
86
+ e5 = np.full(ncell, -element[i, 4], dtype=np.float64) # left-lat positive in Okada
87
+ e6 = np.full(ncell, element[i, 5], dtype=np.float64)
88
+ zr = np.zeros(ncell, dtype=np.float64)
89
+
90
+ ux, uy, uz, uxx, uyx, uzx, uxy, uyy, uzy, uxz, uyz, uzz, iret = okada_dc3d(
91
+ aa[0], x, y, zz, dp, e7, al, al, aw, aw, e5, e6, zr
92
+ )
93
+ else:
94
+ continue
95
+
96
+ # Displacement Conversion
97
+ sw = np.sqrt((element[i, 3] - element[i, 1])**2 + (element[i, 2] - element[i, 0])**2)
98
+ sina = (element[i, 3] - element[i, 1]) / float(sw)
99
+ cosa = (element[i, 2] - element[i, 0]) / float(sw)
100
+
101
+ uxg = ux * cosa - uy * sina
102
+ uyg = ux * sina + uy * cosa
103
+ uzg = uz
104
+
105
+ # Strain to stress
106
+ sk = young / (1.0 + pois)
107
+ gk = pois / (1.0 - 2.0 * pois)
108
+ vol = uxx + uyy + uzz
109
+
110
+ # Strain dimension is / 1000
111
+ sxx = sk * (gk * vol + uxx) * 0.001
112
+ syy = sk * (gk * vol + uyy) * 0.001
113
+ szz = sk * (gk * vol + uzz) * 0.001
114
+ sxy = (young / (2.0 * (1.0 + pois))) * (uxy + uyx) * 0.001
115
+ sxz = (young / (2.0 * (1.0 + pois))) * (uxz + uzx) * 0.001
116
+ syz = (young / (2.0 * (1.0 + pois))) * (uyz + uzy) * 0.001
117
+
118
+ s0 = np.array([sxx, syy, szz, syz, sxz, sxy]) # shape (6, ncell)
119
+
120
+ # Strain Conversion
121
+ s1 = tensor_trans(sina, cosa, s0)
122
+
123
+ sxx_n = s1[0, :]
124
+ syy_n = s1[1, :]
125
+ szz_n = s1[2, :]
126
+ syz_n = s1[3, :]
127
+ sxz_n = s1[4, :]
128
+ sxy_n = s1[5, :]
129
+
130
+ dc3d0_arr = np.column_stack([
131
+ xycoord[:, 0], xycoord[:, 1], x, y, zz,
132
+ uxg, uyg, uzg, sxx_n, syy_n, szz_n, syz_n, sxz_n, sxy_n
133
+ ])
134
+
135
+ if i == 0:
136
+ dc3d0_final = np.column_stack([
137
+ xycoord[:, 0], xycoord[:, 1], x, y, zz,
138
+ uxg, uyg, uzg, sxx_n, syy_n, szz_n, syz_n, sxz_n, sxy_n
139
+ ])
140
+ else:
141
+ dc3d0_final = np.column_stack([
142
+ np.zeros(ncell), np.zeros(ncell), np.zeros(ncell), np.zeros(ncell), np.zeros(ncell),
143
+ uxg, uyg, uzg, sxx_n, syy_n, szz_n, syz_n, sxz_n, sxy_n
144
+ ])
145
+
146
+ dc3d_out += dc3d0_final
147
+
148
+ return dc3d_out
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: cfs-python
3
+ Version: 0.1.0
4
+ Summary: Python-based Coulomb Stress Change UI and API
5
+ Home-page: https://github.com/yudhastyawan/cfs-python
6
+ Author: Yudha Styawan
7
+ Author-email: yudhastyawan97@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Scientific/Engineering :: Physics
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: numpy
15
+ Requires-Dist: pandas
16
+ Requires-Dist: panel
17
+ Requires-Dist: plotly
18
+ Requires-Dist: param
19
+ Requires-Dist: geopandas
20
+ Requires-Dist: rasterio
21
+ Requires-Dist: shapely
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+ Dynamic: summary
31
+
32
+ # PyCFS Dashboard
33
+
34
+ An interactive dashboard for visualizing and computing Coulomb Stress Changes.
35
+ Powered by Python (`numpy`), `Panel`, and `Plotly`.
36
+
37
+ ## Features
38
+ - Interactive 2D and 3D map views of fault sources and computed stress variables.
39
+ - Dynamically extract Cross-Sectional geometries over user-defined paths.
40
+ - Support for Single Point (Lat/Lon or Km), Grid Box mapping, and Custom Receivers matching algorithms.
41
+ - Custom Scientific Colormaps configurations (`Viridis`, `Jet`, `balance`, etc.) with manual boundary values (`vmin`/`vmax`).
42
+ - High-fidelity exporting: Results available in `.csv` (coordinates included), Georeferenced TIF, and Esri `.shp`.
43
+
44
+ ## Interface Snapshot
45
+ This toolkit renders directly in the browser via native WebSockets using the pure Python `Panel` framework.
46
+
47
+ ## Usage
48
+ Simply start the dashboard interface locally with:
49
+ ```bash
50
+ panel serve app_panel.py --show
51
+ ```
@@ -0,0 +1,11 @@
1
+ app_panel.py,sha256=S2Zp4FtIUtJ0yQqIn-VZWviaa-Yxn56UDzVU5UG5iXk,39958
2
+ cfs_lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ cfs_lib/coulomb_math.py,sha256=R8sH1EOs-7R-u3d5mahYba5QsG92rI4MlltbRLyWBDU,3961
4
+ cfs_lib/io_parser.py,sha256=TIhzKnvKj8pG3ztscx_xhh6vevEOV-iCnBt8E8D0i-c,5910
5
+ cfs_lib/main.py,sha256=ZpmG5CIp4-0QCg2zW6df6Jve6jLdVKhyNN6gbO66pmE,7084
6
+ cfs_lib/okada_math.py,sha256=9lhVBLCotw-L9tihPJQ2G1z8KA-ObYRgkSmkitBrLvM,27286
7
+ cfs_lib/okada_wrapper.py,sha256=ujL_2F3jyWCE3lwBvmjf4aPaFxqy_d7753QFNyRYPNw,5931
8
+ cfs_python-0.1.0.dist-info/METADATA,sha256=AXb8zj2zuunn6wxVAJcbT9Hle4tkykonFt_3-qAY4BE,1765
9
+ cfs_python-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
10
+ cfs_python-0.1.0.dist-info/top_level.txt,sha256=hWJkKJsmaKZ_8J8tBskSYHxGpCIoNdrkET9c195c5-o,18
11
+ cfs_python-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ app_panel
2
+ cfs_lib