Skip to content

Commit 1f002cf

Browse files
committed
update
1 parent ae6cb82 commit 1f002cf

334 files changed

Lines changed: 58507 additions & 11045 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.appdata/pygimli/Cache/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.5.4

.appdata/pygimli/config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"globalCache": true,
3+
"lang": "eng",
4+
"pyvista.backend": "client",
5+
"unitStyle": 2,
6+
"view3D": "auto",
7+
"waitOnExit": true
8+
}

.claude/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(cd:*)"
5+
]
6+
}
7+
}

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"Bash(conda info:*)",
66
"Bash(conda activate:*)",
77
"Bash(/c/ProgramData/anaconda3/envs/pg/python.exe:*)",
8-
"Bash(/c/Users/hchen117/.conda/envs/pg/python.exe:*)"
8+
"Bash(/c/Users/hchen117/.conda/envs/pg/python.exe:*)",
9+
"Bash(wc -l:*)"
910
]
1011
}
1112
}

PyHydroGeophysX/Hydro_modular/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44

55
from PyHydroGeophysX.Hydro_modular.hydro_to_ert import hydro_to_ert
66
from PyHydroGeophysX.Hydro_modular.hydro_to_srt import hydro_to_srt
7+
from PyHydroGeophysX.Hydro_modular.hydro_to_tdem import hydro_to_tdem
8+
from PyHydroGeophysX.Hydro_modular.hydro_to_fdem import hydro_to_fdem
9+
from PyHydroGeophysX.Hydro_modular.hydro_to_gravity import hydro_to_gravity
710

811
__all__ = [
912
'hydro_to_ert',
10-
'hydro_to_srt'
11-
]
13+
'hydro_to_srt',
14+
'hydro_to_tdem',
15+
'hydro_to_fdem',
16+
'hydro_to_gravity'
17+
]
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
"""
2+
Hydrologic-to-FDEM conversion helpers for 2D profile workflows.
3+
"""
4+
5+
from typing import Optional, Tuple
6+
7+
import numpy as np
8+
9+
from PyHydroGeophysX.forward.fdem_forward import FDEMForwardModeling
10+
11+
12+
def _validate_profile_inputs(
13+
water_content: np.ndarray,
14+
porosity: np.ndarray,
15+
layer_boundaries: np.ndarray,
16+
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
17+
wc = np.asarray(water_content, dtype=float)
18+
phi = np.asarray(porosity, dtype=float)
19+
boundaries = np.asarray(layer_boundaries, dtype=float)
20+
21+
if wc.ndim != 2:
22+
raise ValueError(
23+
f"water_content must be 2D (n_layers, n_stations), got shape {wc.shape}."
24+
)
25+
if phi.shape != wc.shape:
26+
raise ValueError(
27+
f"porosity shape {phi.shape} must match water_content shape {wc.shape}."
28+
)
29+
30+
n_layers, n_stations = wc.shape
31+
32+
if boundaries.ndim == 1:
33+
if boundaries.size != n_layers + 1:
34+
raise ValueError(
35+
"1D layer_boundaries must have n_layers + 1 values."
36+
)
37+
boundaries = np.repeat(boundaries[:, np.newaxis], n_stations, axis=1)
38+
elif boundaries.ndim == 2:
39+
expected = (n_layers + 1, n_stations)
40+
if boundaries.shape != expected:
41+
raise ValueError(
42+
f"layer_boundaries shape must be {expected}, got {boundaries.shape}."
43+
)
44+
else:
45+
raise ValueError("layer_boundaries must be 1D or 2D.")
46+
47+
return wc, phi, boundaries
48+
49+
50+
def hydro_to_fdem(
51+
water_content: np.ndarray,
52+
porosity: np.ndarray,
53+
layer_boundaries: np.ndarray,
54+
frequencies: Optional[np.ndarray] = None,
55+
sigma_w: float = 0.05,
56+
m: float = 1.5,
57+
n: float = 2.0,
58+
sigma_s: float = 0.0,
59+
source_location: Optional[np.ndarray] = None,
60+
receiver_location: Optional[np.ndarray] = None,
61+
source_radius: float = 10.0,
62+
receiver_orientation: str = "z",
63+
receiver_component: str = "secondary",
64+
waveform_type: str = "dipole",
65+
noise_level: float = 0.03,
66+
seed: Optional[int] = None,
67+
min_thickness: float = 0.1,
68+
verbose: bool = False,
69+
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
70+
"""
71+
Simulate pseudo-2D FDEM response from one hydrologic profile.
72+
73+
A 1D FDEM sounding is simulated at each profile station and stacked into a
74+
response matrix.
75+
76+
Args:
77+
water_content: Water content matrix, shape (n_layers, n_stations).
78+
porosity: Porosity matrix, same shape as water_content.
79+
layer_boundaries: Elevation matrix for layer interfaces,
80+
shape (n_layers + 1, n_stations), or 1D (n_layers + 1).
81+
frequencies: FDEM frequencies.
82+
sigma_w: Pore-water conductivity (S/m).
83+
m: Cementation exponent.
84+
n: Saturation exponent.
85+
sigma_s: Surface conductivity (S/m).
86+
source_location: Source location [x, y, z].
87+
receiver_location: Receiver location [x, y, z].
88+
source_radius: Source loop radius (m).
89+
receiver_orientation: Receiver orientation.
90+
receiver_component: 'secondary', 'total', or 'both'.
91+
waveform_type: 'dipole' or 'loop'.
92+
noise_level: Relative noise level.
93+
seed: Random seed.
94+
min_thickness: Lower bound for finite layer thicknesses (m).
95+
verbose: Print progress.
96+
97+
Returns:
98+
noisy_data: Shape (n_stations, n_frequencies), complex.
99+
clean_data: Shape (n_stations, n_frequencies), complex.
100+
uncertainty: Shape (n_stations, n_frequencies), float.
101+
conductivity: Shape (n_layers, n_stations), float.
102+
"""
103+
wc, phi, boundaries = _validate_profile_inputs(
104+
water_content=water_content,
105+
porosity=porosity,
106+
layer_boundaries=layer_boundaries,
107+
)
108+
109+
n_layers, n_stations = wc.shape
110+
thicknesses_all = np.clip(
111+
np.abs(np.diff(boundaries, axis=0)),
112+
min_thickness,
113+
None,
114+
)
115+
116+
if frequencies is None:
117+
frequencies = np.logspace(1, 4, 16)
118+
119+
if source_location is None:
120+
source_location = np.array([0.0, 0.0, 0.0], dtype=float)
121+
else:
122+
source_location = np.asarray(source_location, dtype=float)
123+
124+
if receiver_location is None:
125+
receiver_location = np.array([10.0, 0.0, 0.0], dtype=float)
126+
else:
127+
receiver_location = np.asarray(receiver_location, dtype=float)
128+
129+
clean_matrix = None
130+
noisy_matrix = None
131+
unc_matrix = None
132+
conductivity = np.zeros((n_layers, n_stations), dtype=float)
133+
134+
base_rng = np.random.default_rng(seed)
135+
local_seeds = base_rng.integers(0, 2**31 - 1, size=n_stations)
136+
137+
for j in range(n_stations):
138+
if n_layers > 1:
139+
finite_thickness = thicknesses_all[:-1, j]
140+
else:
141+
finite_thickness = np.array([], dtype=float)
142+
143+
noisy_j, clean_j, unc_j, cond_j = FDEMForwardModeling.hydro_to_fdem(
144+
water_content=wc[:, j],
145+
porosity=phi[:, j],
146+
layer_thicknesses=finite_thickness,
147+
sigma_w=sigma_w,
148+
m=m,
149+
n=n,
150+
sigma_s=sigma_s,
151+
frequencies=frequencies,
152+
source_location=source_location,
153+
receiver_location=receiver_location,
154+
source_radius=source_radius,
155+
receiver_orientation=receiver_orientation,
156+
receiver_component=receiver_component,
157+
waveform_type=waveform_type,
158+
noise_level=noise_level,
159+
seed=int(local_seeds[j]),
160+
)
161+
162+
clean_j = np.asarray(clean_j).ravel()
163+
noisy_j = np.asarray(noisy_j).ravel()
164+
unc_j = np.asarray(unc_j, dtype=float).ravel()
165+
166+
if clean_matrix is None:
167+
n_freq = clean_j.size
168+
clean_matrix = np.zeros((n_stations, n_freq), dtype=np.complex128)
169+
noisy_matrix = np.zeros((n_stations, n_freq), dtype=np.complex128)
170+
unc_matrix = np.zeros((n_stations, n_freq), dtype=float)
171+
172+
clean_matrix[j, :] = clean_j
173+
noisy_matrix[j, :] = noisy_j
174+
unc_matrix[j, :] = unc_j
175+
conductivity[:, j] = np.asarray(cond_j, dtype=float).ravel()
176+
177+
if verbose:
178+
c_min = float(np.nanmin(conductivity))
179+
c_max = float(np.nanmax(conductivity))
180+
print(
181+
f"FDEM profile simulation complete: stations={n_stations}, "
182+
f"layers={n_layers}, conductivity={c_min:.4e}-{c_max:.4e} S/m"
183+
)
184+
185+
return noisy_matrix, clean_matrix, unc_matrix, conductivity

0 commit comments

Comments
 (0)