cwadayi commited on
Commit
e971733
·
verified ·
1 Parent(s): 5bc29f9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -0
app.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+
5
+ # --- 核心計算與繪圖函數 ---
6
+ def plot_seismic_refraction(v1, v2, h, x_max):
7
+ """
8
+ 根據輸入的地層參數,計算並繪製折射震測的走時曲線。
9
+
10
+ 參數:
11
+ v1 (float): 第一層介質速度 (m/s)
12
+ v2 (float): 第二層介質速度 (m/s)
13
+ h (float): 第一層介質厚度 (m)
14
+ x_max (float): 模擬的最大測線距離 (m)
15
+
16
+ 返回:
17
+ matplotlib.figure: 走時曲線圖
18
+ str: 包含計算結果的 Markdown 格式化文字
19
+ """
20
+ # 物理條件檢查:折射必須 V2 > V1
21
+ if v2 <= v1:
22
+ # 建立一個空的圖表並顯示錯誤訊息
23
+ fig, ax = plt.subplots()
24
+ ax.text(0.5, 0.5, '錯誤:V2 必須大於 V1 才能產生臨界折射!\n(Error: V2 must be greater than V1 for critical refraction to occur.)',
25
+ ha='center', va='center', fontsize=12, color='red')
26
+ ax.set_xlabel("與震源的距離 (Distance, m)")
27
+ ax.set_ylabel("傳播時間 (Travel Time, s)")
28
+ ax.grid(True)
29
+ ax.set_title("走時曲線 (Travel-Time Curve)")
30
+ return fig, "### 參數錯誤\n請確保第二層速度 (V2) 大於第一層速度 (V1)。"
31
+
32
+ # 1. 計算關鍵物理量
33
+ # 臨界角 (radians and degrees)
34
+ theta_c_rad = np.arcsin(v1 / v2)
35
+ theta_c_deg = np.rad2deg(theta_c_rad)
36
+
37
+ # 截時 (Intercept Time, ti)
38
+ ti = (2 * h * np.cos(theta_c_rad)) / v1
39
+
40
+ # 交越距離 (Crossover Distance, xc)
41
+ xc = 2 * h * np.sqrt((v2 + v1) / (v2 - v1))
42
+
43
+ # 2. 準備繪圖數據
44
+ x = np.linspace(0, x_max, 500)
45
+
46
+ # 直達波走時 (Direct Wave)
47
+ t_direct = x / v1
48
+
49
+ # 折射波走時 (Refracted Wave)
50
+ t_refracted = (x / v2) + ti
51
+
52
+ # 實際的初達波 (First Arrival)
53
+ t_first_arrival = np.minimum(t_direct, t_refracted)
54
+
55
+ # 3. 使用 Matplotlib 繪圖
56
+ fig, ax = plt.subplots(figsize=(10, 6))
57
+
58
+ # 繪製各波線
59
+ ax.plot(x, t_direct, 'b--', label=f'直達波 (Direct Wave) - 斜率 1/{v1:.0f}')
60
+ ax.plot(x, t_refracted, 'g--', label=f'折射波 (Refracted Wave) - 斜率 1/{v2:.0f}')
61
+ ax.plot(x, t_first_arrival, 'r-', linewidth=3, label='初達波 (First Arrival)')
62
+
63
+ # 標示交越距離
64
+ if xc < x_max:
65
+ ax.axvline(x=xc, color='k', linestyle=':', label=f'交越距離 (Crossover) = {xc:.1f} m')
66
+ ax.plot(xc, xc/v1, 'ko') # 標示交越點
67
+
68
+ # 標示截時
69
+ ax.plot(0, ti, 'mo', markersize=8, label=f'截時 (Intercept) = {ti*1000:.1f} ms')
70
+
71
+ # 設定圖表樣式
72
+ ax.set_title("互動式震測折射走時圖", fontsize=16)
73
+ ax.set_xlabel("與震源的距離 (Distance, m)", fontsize=12)
74
+ ax.set_ylabel("傳播時間 (Travel Time, s)", fontsize=12)
75
+ ax.legend()
76
+ ax.grid(True)
77
+ ax.set_xlim(0, x_max)
78
+ ax.set_ylim(0, max(t_direct) * 1.1)
79
+
80
+ plt.tight_layout()
81
+
82
+ # 4. 準備輸出的說明文字 (Markdown 格式)
83
+ results_md = f"""
84
+ ### 🔬 分析結果
85
+
86
+ 根據您設定的參數,我們計算出以下關鍵物理量:
87
+
88
+ - **臨界角 (Critical Angle, θc)**:
89
+ - 公式: `θc = arcsin(V1 / V2)`
90
+ - 計算: `arcsin({v1:.0f} / {v2:.0f})` = **{theta_c_deg:.2f}°**
91
+ - *這是產生「抄捷徑」折射波的關鍵入射角度。*
92
+
93
+ - **截時 (Intercept Time, tᵢ)**:
94
+ - 公式: `tᵢ = (2 * h * cos(θc)) / V1`
95
+ - 計算: `(2 * {h:.0f} * cos({theta_c_deg:.2f}°)) / {v1:.0f}` = **{ti*1000:.1f} ms**
96
+ - *這是折射波走時線在時間軸上的截距,它隱含了第一層的厚度資訊。*
97
+
98
+ - **交越距離 (Crossover Distance, Xc)**:
99
+ - 公式: `Xc = 2 * h * sqrt((V2 + V1) / (V2 - V1))`
100
+ - 計算: `2 * {h:.0f} * sqrt(({v2:.0f} + {v1:.0f}) / ({v2:.0f} - {v1:.0f}))` = **{xc:.1f} m**
101
+ - *在這個距離上,直達波和折射波會同時抵達。超過這個距離後,折射波會先到。*
102
+ """
103
+
104
+ return fig, results_md
105
+
106
+ # --- Gradio 介面設定 ---
107
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
108
+ gr.Markdown("# 地心震波奇幻之旅:互動折射震測實驗室 🌍")
109
+ gr.Markdown(
110
+ """
111
+ 歡迎來到地球物理小教室!這個互動工具是根據「地心震波奇幻之旅」課程內容設計的。
112
+ 您可以透過下方的滑桿來模擬一個簡單的雙層地層模型。調整第一層的速度 `V1`、第二層的速度 `V2` 以及第一層的厚度 `h`,
113
+ 觀察右側的「走時-距離圖」如何即時變化,並從中學習折射震測法的核心原理!
114
+ """
115
+ )
116
+
117
+ with gr.Row():
118
+ with gr.Column(scale=1):
119
+ gr.Markdown("### ⚙️ 調整地層參數")
120
+ v1_slider = gr.Slider(label="V1: 第一層速度 (m/s)", minimum=300, maximum=3000, value=800, step=50)
121
+ v2_slider = gr.Slider(label="V2: 第二層速度 (m/s)", minimum=500, maximum=6000, value=2500, step=50)
122
+ h_slider = gr.Slider(label="h: 第一層厚度 (m)", minimum=5, maximum=100, value=20, step=1)
123
+ xmax_slider = gr.Slider(label="最大觀測距離 (m)", minimum=100, maximum=500, value=250, step=10)
124
+
125
+ submit_btn = gr.Button("產生圖表", variant="primary")
126
+
127
+ with gr.Column(scale=2):
128
+ gr.Markdown("### 📊 走時-距離圖 (T-X Plot)")
129
+ plot_output = gr.Plot()
130
+
131
+ with gr.Row():
132
+ results_output = gr.Markdown("### 🔬 分析結果\n請調整參數並點擊按鈕以顯示計算結果。")
133
+
134
+ # --- 事件監聽 ---
135
+ submit_btn.click(
136
+ fn=plot_seismic_refraction,
137
+ inputs=[v1_slider, v2_slider, h_slider, xmax_slider],
138
+ outputs=[plot_output, results_output]
139
+ )
140
+
141
+ gr.Markdown(
142
+ """
143
+ ---
144
+ ### 學習重點
145
+ 1. **觀察斜率**: 直達波的斜率是 `1/V1`,折射波的斜率是 `1/V2`。試著調整 `V1` 和 `V2`,看看線條的陡峭程度如何變化?(速度越快,線越陡,斜率越小)。
146
+ 2. **觀察截時 (Intercept Time)**: 試著只增加厚度 `h`,看看綠色虛線在 Y 軸上的截距有什麼變化?(厚度越厚,截時越大)。
147
+ 3. **觀察交越距離 (Crossover Distance)**: 試著增加 `h` 或減小 `V2` 與 `V1` 的速度差,看看紅線與藍線的交叉點 (黑色垂直虛線) 如何向右移動?
148
+ 4. **必要條件**: 試著將 `V2` 調整到比 `V1` 小,看看會發生什麼事?你會發現,臨界折射的現象消失了!
149
+
150
+ <footer>
151
+ <p style="text-align:center; color:grey;">地球物理小教室 &copy; 2025 - 由 Gemini 根據課程文件生成</p>
152
+ </footer>
153
+ """
154
+ )
155
+
156
+ if __name__ == "__main__":
157
+ demo.launch()
158
+