cwadayi commited on
Commit
28681db
·
verified ·
1 Parent(s): c4e778c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -18
app.py CHANGED
@@ -4,19 +4,23 @@ import matplotlib.pyplot as plt
4
 
5
  # --- 輔助函數:產生 Ricker 震波 ---
6
  def ricker_wavelet(t, f=25.0):
7
- t = t - 2.0 / f
 
8
  p = (np.pi * f * t) ** 2
9
  return (1 - 2 * p) * np.exp(-p)
10
 
11
  # --- 核心計算與繪圖函數 ---
12
- def plot_seismic_exploration(v1, v2, v3, h1, h2, x_max, num_receivers, gain):
 
 
 
 
13
  # === PART 1: 物理計算 (升級至三層模型) ===
14
- # 物理條件檢查
15
  valid_model = True
16
  error_msg = ""
17
  if v2 <= v1 or v3 <= v2:
18
  valid_model = False
19
- error_msg = "### 模型錯誤\n速度必須隨深度增加 (V3 > V2 > V1)"
20
 
21
  # 計算關鍵物理量 (第一層介面)
22
  t0_1 = (2 * h1) / v1
@@ -27,55 +31,57 @@ def plot_seismic_exploration(v1, v2, v3, h1, h2, x_max, num_receivers, gain):
27
  fig0, ax0 = plt.subplots(figsize=(10, 2))
28
  ax0.set_xlim(0, x_max)
29
  ax0.set_ylim(-(h1 + h2) * 1.5, 5)
30
- ax0.axhline(0, color='brown', linewidth=3)
31
  ax0.axhline(-h1, color='gray', linestyle='--')
32
  ax0.axhline(-(h1+h2), color='darkgray', linestyle='--')
33
  ax0.fill_between([0, x_max], 0, -h1, color='sandybrown', alpha=0.6)
34
  ax0.fill_between([0, x_max], -h1, -(h1+h2), color='darkkhaki', alpha=0.6)
35
  ax0.fill_between([0, x_max], -(h1+h2), -(h1 + h2) * 1.5, color='dimgray', alpha=0.6)
36
- ax0.text(x_max/2, -h1/2, f'Layer 1\nV1 = {v1:.0f} m/s\nh1 = {h1:.0f} m', ha='center', va='center', fontsize=10, color='black')
37
- ax0.text(x_max/2, -h1-h2/2, f'Layer 2\nV2 = {v2:.0f} m/s\nh2 = {h2:.0f} m', ha='center', va='center', fontsize=10, color='black')
38
- ax0.text(x_max/2, -(h1+h2)*1.25, f'Layer 3 (Basement)\nV3 = {v3:.0f} m/s', ha='center', va='center', fontsize=10, color='white')
39
  ax0.set_title("Geological Model Cross-section")
40
  ax0.set_ylabel("Depth (m)")
41
  ax0.set_yticks([0, -h1, -(h1+h2)])
42
  ax0.set_xticks([])
 
43
 
44
  # === PART 3: 繪製 T-X 走時曲線圖 ===
45
  x_continuous = np.linspace(0, x_max, 500)
46
- # 反射波
 
47
  t_refl_1 = np.sqrt(t0_1**2 + (x_continuous / v1)**2)
48
- t_refl_2 = np.sqrt(t0_2**2 + (x_continuous / ((v1*h1 + v2*h2)/(h1+h2)) )**2) # RMS velocity approximation
49
 
50
  fig1, ax1 = plt.subplots(figsize=(10, 6))
51
  ax1.plot(x_continuous, t_refl_1, 'm:', linewidth=2, label='Reflection 1 (from Layer 2)')
52
  ax1.plot(x_continuous, t_refl_2, 'c:', linewidth=2, label='Reflection 2 (from Layer 3)')
53
 
54
- # 折射波 (僅在速度增加時繪製)
55
  if valid_model:
56
  theta_c12 = np.arcsin(v1 / v2)
57
  ti_12 = (2 * h1 * np.cos(theta_c12)) / v1
58
  t_refr_12 = (x_continuous / v2) + ti_12
59
  ax1.plot(x_continuous, t_refr_12, 'g--', label='Refraction (from Layer 2)')
60
 
61
- theta_c23 = np.arcsin(v2 / v3)
62
- ti_23 = 2 * h1 * np.cos(np.arcsin(v1/v3))/v1 + 2 * h2 * np.cos(theta_c23)/v2
63
  t_refr_23 = (x_continuous / v3) + ti_23
64
  ax1.plot(x_continuous, t_refr_23, 'y--', label='Refraction (from Layer 3)')
65
 
66
  ax1.set_title("1. Travel-Time (T-X) Curve")
67
- ax1.legend()
68
  ax1.grid(True)
69
  ax1.set_xlim(0, x_max)
70
  y_max = np.max(t_refl_2) * 1.1
71
  ax1.set_ylim(0, y_max)
 
72
 
73
  # === PART 4: 繪製視覺化震測剖面圖 ===
74
  fig2, ax2 = plt.subplots(figsize=(10, 5))
75
  receiver_x = np.linspace(0, x_max, int(num_receivers))
76
  # 反射波到時
77
  t_refl_1_rx = np.sqrt(t0_1**2 + (receiver_x / v1)**2)
78
- t_refl_2_rx = np.sqrt(t0_2**2 + (receiver_x / ((v1*h1 + v2*h2)/(h1+h2)) )**2)
79
 
80
  wavelet_duration = y_max / 10
81
  wavelet_t = np.linspace(0, wavelet_duration, 100)
@@ -103,14 +109,14 @@ def plot_seismic_exploration(v1, v2, v3, h1, h2, x_max, num_receivers, gain):
103
  # === PART 5: 準備探勘日誌 ===
104
  log_md = f"""
105
  ### 📝 現場探勘日誌
106
- **任務目標**: {scenario_name.get() if 'scenario_name' in globals() else '自訂模式'}
107
  **儀器設定**: {int(num_receivers)} 個測站, 測線長度 {x_max} 公尺。
108
 
109
  **初步分析**:
110
  - **第一介面反射 (黑色震波)**: 雙程走時 (TWT) 約 **{t0_1*1000:.1f} ms**。
111
  - **第二介面反射 (藍色震波)**: 雙程走時 (TWT) 約 **{t0_2*1000:.1f} ms**。
112
 
113
- {'' if valid_model else '**警告**: 模型速度設定有誤 (V 未隨深度增加),折射波分析可能無效。'}
114
  """
115
  return fig0, fig1, fig2, log_md
116
 
@@ -167,9 +173,10 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
167
  )
168
  scenario_dropdown.change(lambda x: x, inputs=scenario_dropdown, outputs=scenario_name)
169
 
 
170
  submit_btn.click(
171
  fn=plot_seismic_exploration,
172
- inputs=[v1_slider, v2_slider, v3_slider, h1_slider, h2_slider, xmax_slider, receivers_slider, gain_slider],
173
  outputs=[plot_output0, plot_output1, plot_output2, log_output]
174
  )
175
 
 
4
 
5
  # --- 輔助函數:產生 Ricker 震波 ---
6
  def ricker_wavelet(t, f=25.0):
7
+ """ 產生一個 Ricker 震波 (墨西哥帽函數) """
8
+ t = t - 2.0 / f # 將震波峰值對齊時間點
9
  p = (np.pi * f * t) ** 2
10
  return (1 - 2 * p) * np.exp(-p)
11
 
12
  # --- 核心計算與繪圖函數 ---
13
+ # 【*** FIX 1: Add scenario_name_val as a function parameter ***】
14
+ def plot_seismic_exploration(scenario_name_val, v1, v2, v3, h1, h2, x_max, num_receivers, gain):
15
+ """
16
+ 根據輸入的地層參數,計算並繪製所有探勘圖表。
17
+ """
18
  # === PART 1: 物理計算 (升級至三層模型) ===
 
19
  valid_model = True
20
  error_msg = ""
21
  if v2 <= v1 or v3 <= v2:
22
  valid_model = False
23
+ error_msg = "### ⚠️ 模型警告\n速度必須隨深度增加 (V3 > V2 > V1),折射波分析可能無效。"
24
 
25
  # 計算關鍵物理量 (第一層介面)
26
  t0_1 = (2 * h1) / v1
 
31
  fig0, ax0 = plt.subplots(figsize=(10, 2))
32
  ax0.set_xlim(0, x_max)
33
  ax0.set_ylim(-(h1 + h2) * 1.5, 5)
34
+ ax0.axhline(0, color='saddlebrown', linewidth=3)
35
  ax0.axhline(-h1, color='gray', linestyle='--')
36
  ax0.axhline(-(h1+h2), color='darkgray', linestyle='--')
37
  ax0.fill_between([0, x_max], 0, -h1, color='sandybrown', alpha=0.6)
38
  ax0.fill_between([0, x_max], -h1, -(h1+h2), color='darkkhaki', alpha=0.6)
39
  ax0.fill_between([0, x_max], -(h1+h2), -(h1 + h2) * 1.5, color='dimgray', alpha=0.6)
40
+ ax0.text(x_max/2, -h1/2, f'Layer 1\nV1 = {v1:.0f} m/s\nh1 = {h1:.0f} m', ha='center', va='center', fontsize=9, color='black')
41
+ ax0.text(x_max/2, -h1-h2/2, f'Layer 2\nV2 = {v2:.0f} m/s\nh2 = {h2:.0f} m', ha='center', va='center', fontsize=9, color='black')
42
+ ax0.text(x_max/2, -(h1+h2)*1.25, f'Layer 3 (Basement)\nV3 = {v3:.0f} m/s', ha='center', va='center', fontsize=9, color='white')
43
  ax0.set_title("Geological Model Cross-section")
44
  ax0.set_ylabel("Depth (m)")
45
  ax0.set_yticks([0, -h1, -(h1+h2)])
46
  ax0.set_xticks([])
47
+ fig0.tight_layout(pad=1.1)
48
 
49
  # === PART 3: 繪製 T-X 走時曲線圖 ===
50
  x_continuous = np.linspace(0, x_max, 500)
51
+ # 反射波 (使用RMS速度近似)
52
+ v_rms_2 = np.sqrt((v1**2 * 2*h1/v1 + v2**2 * 2*h2/v2) / (2*h1/v1 + 2*h2/v2))
53
  t_refl_1 = np.sqrt(t0_1**2 + (x_continuous / v1)**2)
54
+ t_refl_2 = np.sqrt(t0_2**2 + (x_continuous / v_rms_2)**2)
55
 
56
  fig1, ax1 = plt.subplots(figsize=(10, 6))
57
  ax1.plot(x_continuous, t_refl_1, 'm:', linewidth=2, label='Reflection 1 (from Layer 2)')
58
  ax1.plot(x_continuous, t_refl_2, 'c:', linewidth=2, label='Reflection 2 (from Layer 3)')
59
 
60
+ # 折射波
61
  if valid_model:
62
  theta_c12 = np.arcsin(v1 / v2)
63
  ti_12 = (2 * h1 * np.cos(theta_c12)) / v1
64
  t_refr_12 = (x_continuous / v2) + ti_12
65
  ax1.plot(x_continuous, t_refr_12, 'g--', label='Refraction (from Layer 2)')
66
 
67
+ ti_23 = 2 * h1 * np.sqrt(v3**2 - v1**2)/(v1*v3) + 2 * h2 * np.sqrt(v3**2 - v2**2)/(v2*v3)
 
68
  t_refr_23 = (x_continuous / v3) + ti_23
69
  ax1.plot(x_continuous, t_refr_23, 'y--', label='Refraction (from Layer 3)')
70
 
71
  ax1.set_title("1. Travel-Time (T-X) Curve")
72
+ ax1.legend(fontsize='small')
73
  ax1.grid(True)
74
  ax1.set_xlim(0, x_max)
75
  y_max = np.max(t_refl_2) * 1.1
76
  ax1.set_ylim(0, y_max)
77
+ fig1.tight_layout(pad=1.1)
78
 
79
  # === PART 4: 繪製視覺化震測剖面圖 ===
80
  fig2, ax2 = plt.subplots(figsize=(10, 5))
81
  receiver_x = np.linspace(0, x_max, int(num_receivers))
82
  # 反射波到時
83
  t_refl_1_rx = np.sqrt(t0_1**2 + (receiver_x / v1)**2)
84
+ t_refl_2_rx = np.sqrt(t0_2**2 + (receiver_x / v_rms_2)**2)
85
 
86
  wavelet_duration = y_max / 10
87
  wavelet_t = np.linspace(0, wavelet_duration, 100)
 
109
  # === PART 5: 準備探勘日誌 ===
110
  log_md = f"""
111
  ### 📝 現場探勘日誌
112
+ **任務目標**: {scenario_name_val}
113
  **儀器設定**: {int(num_receivers)} 個測站, 測線長度 {x_max} 公尺。
114
 
115
  **初步分析**:
116
  - **第一介面反射 (黑色震波)**: 雙程走時 (TWT) 約 **{t0_1*1000:.1f} ms**。
117
  - **第二介面反射 (藍色震波)**: 雙程走時 (TWT) 約 **{t0_2*1000:.1f} ms**。
118
 
119
+ {error_msg}
120
  """
121
  return fig0, fig1, fig2, log_md
122
 
 
173
  )
174
  scenario_dropdown.change(lambda x: x, inputs=scenario_dropdown, outputs=scenario_name)
175
 
176
+ # 【*** FIX 2: Add scenario_name to the inputs list ***】
177
  submit_btn.click(
178
  fn=plot_seismic_exploration,
179
+ inputs=[scenario_name, v1_slider, v2_slider, v3_slider, h1_slider, h2_slider, xmax_slider, receivers_slider, gain_slider],
180
  outputs=[plot_output0, plot_output1, plot_output2, log_output]
181
  )
182