Aoi785 commited on
Commit
1f91ed1
ยท
verified ยท
1 Parent(s): 5f4e420

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -152
app.py CHANGED
@@ -1,38 +1,24 @@
1
  import gradio as gr
2
 
3
- # ---------------------------
4
- # Small-Hydro 4-Mode Simulator (Web, Gradio)
5
- # ---------------------------
 
6
 
7
- RHO = 1000.0 # kg/m^3
8
- G = 9.80665 # m/s^2
9
- PF_TARGET = 0.98 # ์—ญ๋ฅ  ๋ชฉํ‘œ ํ‘œ๊ธฐ์šฉ
10
-
11
- # ํšจ์œจ ๊ทผ์‚ฌ: Kaplan/Crossflow ๋ถ€๋ถ„๋ถ€ํ•˜ ํ•ฉ์„ฑ (์ƒ๋Œ€์œ ๋Ÿ‰ r=Q/Qn)
12
  def efficiency_from_relative_flow(r: float) -> float:
13
  r = max(0.0, min(1.2, r))
14
- curve = [
15
- (0.00, 0.00),
16
- (0.10, 0.40),
17
- (0.30, 0.60),
18
- (0.50, 0.75),
19
- (0.70, 0.85),
20
- (0.90, 0.90),
21
- (1.00, 0.91),
22
- (1.20, 0.88),
23
- ]
24
- for (x1, y1), (x2, y2) in zip(curve[:-1], curve[1:]):
25
  if x1 <= r <= x2:
26
- t = 0.0 if x2 == x1 else (r - x1) / (x2 - x1)
27
- return y1 + t * (y2 - y1)
28
  return 0.0
29
 
30
- def electrical_power_kw(Q_in: float, head_m: float, eta: float) -> float:
31
- # P [kW] = rho*g*Q*H*eta / 1000
32
  return (RHO * G * Q_in * head_m * max(0.0, min(1.0, eta))) / 1000.0
33
 
34
- def decide_mode(Q_in: float, q_low: float, q_high: float, rain_mm: float, dp_kpa: float,
35
- rain_thr: float, dp_limit: float, emergency: bool) -> str:
36
  if emergency:
37
  return "Emergency"
38
  if Q_in < q_low:
@@ -41,89 +27,7 @@ def decide_mode(Q_in: float, q_low: float, q_high: float, rain_mm: float, dp_kpa
41
  return "Flood"
42
  return "Normal"
43
 
44
- def mode_policy(mode: str, Q_in: float, Qn: float, Hn: float, rain_mm: float):
45
- # ์ƒ๋Œ€ ์œ ๋Ÿ‰/ํšจ์œจ/์ถœ๋ ฅ(์ปคํ…Œ์ผ ์ „)
46
- r = min(Q_in, Qn) / Qn if Qn > 0 else 0.0
47
- eta = efficiency_from_relative_flow(r)
48
- p_kw_raw = electrical_power_kw(min(Q_in, Qn), Hn, eta)
49
-
50
- # ๊ธฐ๋ณธ ์ œ์–ด ๋ณ€์ˆ˜
51
- gate_open_pct = round(min(100.0, max(10.0, r * 100.0)), 1) # ์ทจ์ˆ˜๋ฌธ ๊ฐœ๋„ ์ถ”์ •
52
- guide_vane_pct = gate_open_pct # ๊ฐ€์ด๋“œ๋ฒ ์ธ/ํ”ผ์น˜ ์ถ”์ •
53
- curtail = False
54
- use_bypass = False
55
- dump_load = False
56
- soc_range = (55, 70) # Normal ๊ธฐ๋ณธ
57
-
58
- actions = []
59
-
60
- if mode == "Normal":
61
- soc_range = (55, 70)
62
- actions += [
63
- "๊ฐ€์ด๋“œ๋ฒ ์ธ/ํ”ผ์น˜: PID ์ถ”์ข…์œผ๋กœ ์ถœ๋ ฅ ์ตœ์ ํ™”",
64
- "ESS: SoC 55โ€“70% ์œ ์ง€(์ˆ˜๋ช… ์ตœ์ )",
65
- "ํŠธ๋ž˜์‹œ๋ž™ ฮ”P ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์ฃผ๊ธฐ ์ฒญ์†Œ",
66
- ]
67
-
68
- elif mode == "Flood":
69
- soc_range = (35, 45)
70
- curtail = True
71
- use_bypass = True
72
- dump_load = True
73
- gate_open_pct = max(20.0, gate_open_pct - 20.0) # ์ˆ˜๊ฒฉ ๋ฐฉ์ง€์šฉ ๊ฐ๊ฐœ
74
- guide_vane_pct = gate_open_pct
75
- p_kw_raw *= 0.6 # ์šฐํšŒ/์ปคํ…Œ์ผ ๋ฐ˜์˜ํ•œ ๋ณด์ˆ˜ ์ถœ๋ ฅ
76
- actions += [
77
- "๊ฐ€์ด๋“œ๋ฒ ์ธ ๋‹จ๊ณ„์  ๊ฐ๊ฐœ(์ˆ˜๊ฒฉ ๋ฐฉ์ง€ ๊ณก์„  ์ค€์ˆ˜)",
78
- "์—ฌ์ˆ˜๋กœ/๋ฐ”์ดํŒจ์Šค ๊ฐœ๋ฐฉ, ๋ฐฐ์‚ฌ๋ฌธ ๊ฐ„ํ— ๊ฐœ๋ฐฉ(ํ† ์‚ฌยทํƒ๋„ ์ €๊ฐ)",
79
- "ESS: SoC ๋ชฉํ‘œ 35โ€“45% (๊ฐ•์šฐ ์˜ˆ๋ณด ๋ฐ˜์˜)",
80
- "๋คํ”„๋กœ๋“œ/๊ฐ€๋ณ€๋ถ€ํ•˜ ์šฐ์„  ๊ฐ€๋™์œผ๋กœ ์ดˆ๊ณผ์ „๋ ฅ ํก์ˆ˜",
81
- "ํŠธ๋ž˜์‹œ๋ž™ ์ž๊ฐ€์ฒญ์†Œ ์—ฐ์† ๊ตฌ๋™(ฮ”P ์ž„๊ณ„ ์ดˆ๊ณผ ์‹œ)",
82
- ]
83
-
84
- elif mode == "Low-Flow":
85
- soc_range = (45, 65)
86
- guide_vane_pct = max(15.0, min(55.0, guide_vane_pct))
87
- gate_open_pct = guide_vane_pct
88
- p_kw_raw *= 0.85 # ๋ถ€๋ถ„๋ถ€ํ•˜ ์†์‹ค
89
- actions += [
90
- "์ €๋ถ€ํ•˜ ํšจ์œจ์ (๊ฐ€๋ณ€์†/๊ฐ๋„ ๊ณ ์ •) ์šด์ „",
91
- "ESS: ํ”ผํฌ ๋ณด์กฐ ๋ฐฉ์ „, SoC 45โ€“65%",
92
- "์œ ์ž…์ˆ˜์†๋„ ํ™•๋ณด(NPSH ์—ฌ์œ  ์œ ์ง€), ๊ณต๋™ํ˜„์ƒ ๊ฐ์‹œ",
93
- ]
94
-
95
- elif mode == "Emergency":
96
- soc_range = (30, 50)
97
- curtail = True
98
- use_bypass = True
99
- dump_load = False
100
- guide_vane_pct = 0.0
101
- gate_open_pct = 0.0
102
- p_kw_raw = 0.0
103
- actions += [
104
- "์ฆ‰์‹œ ๋ฌด๋ถ€ํ•˜ โ†’ ์ •์ง€(์ˆ˜๊ฒฉ ๊ณก์„  ์ค€์ˆ˜)",
105
- "์ทจ์ˆ˜๋ฌธ ํ์‡„ & ๋ฐ”์ดํŒจ์Šค/์Šคํ•„์›จ์ด ๊ฐœ๋ฐฉ(์น˜์ˆ˜ ์•ˆ์ „)",
106
- "๊ณ„ํ†ต ๋ถ„๋ฆฌ, UPS/ESS๋กœ ๊ณ„์žฅ ์ „์› ์œ ์ง€",
107
- "์‚ฌํ›„ ์ ๊ฒ€: ๋ฒ ์–ด๋ง/์ƒคํ”„ํŠธ/๊ด€๋กœ/์„œ์ง€ํƒฑํฌ",
108
- ]
109
- else:
110
- actions.append("์ •์˜๋˜์ง€ ์•Š์€ ๋ชจ๋“œ")
111
-
112
- estimates = {
113
- "์ถ”์ •ํšจ์œจ(eta)": f"{eta:.3f}",
114
- "์ถ”์ •์ถœ๋ ฅ(kW)": f"{p_kw_raw:.1f}",
115
- "์„ค์ •_๊ฐ€์ด๋“œ๋ฒ ์ธ(%)": f"{guide_vane_pct:.1f}",
116
- "์„ค์ •_์ทจ์ˆ˜๋ฌธ๊ฐœ๋„(%)": f"{gate_open_pct:.1f}",
117
- "์ปคํ…Œ์ผ": str(curtail),
118
- "๋ฐ”์ดํŒจ์Šค๊ฐœ๋ฐฉ": str(use_bypass),
119
- "๋คํ”„๋กœ๋“œ๊ฐ€๋™": str(dump_load),
120
- "ESS_SoC_๋ชฉํ‘œ(%)": f"{soc_range[0]}โ€“{soc_range[1]}",
121
- "์—ญ๋ฅ ๋ชฉํ‘œ": f"{PF_TARGET}",
122
- }
123
- return actions, estimates
124
-
125
- def run_sim(Q_in, rain_mm, dp_kpa, emergency,
126
- Hn, Qn, rain_thr, dp_limit):
127
  try:
128
  Q_in = float(Q_in)
129
  rain_mm = float(rain_mm)
@@ -140,58 +44,46 @@ def run_sim(Q_in, rain_mm, dp_kpa, emergency,
140
  q_high = 1.2 * Qn
141
 
142
  mode = decide_mode(Q_in, q_low, q_high, rain_mm, dp_kpa, rain_thr, dp_limit, emergency)
143
- actions, estimates = mode_policy(mode, Q_in, Qn, Hn, rain_mm)
144
-
145
- # ๊ฒฐ๊ณผ๋ฅผ Markdown์œผ๋กœ ์ •๋ฆฌ
146
- md = []
147
- md.append(f"## ์šด์ „ ๋ชจ๋“œ: **{mode}**")
148
- md.append("")
149
- md.append("### ์ž…๋ ฅ ์š”์•ฝ")
150
- md.append(f"- ์œ ๋Ÿ‰ Q: **{Q_in:.2f} mยณ/s**")
151
- md.append(f"- ๊ฐ•์šฐ ์˜ˆ๋ณด: **{rain_mm:.1f} mm/24h**")
152
- md.append(f"- ํŠธ๋ž˜์‹œ๋ž™ ฮ”P: **{dp_kpa:.1f} kPa**")
153
- md.append(f"- ์„ค๊ณ„ ๋‚™์ฐจ Hโ‚™: **{Hn:.2f} m**, ์„ค๊ณ„ ์œ ๋Ÿ‰ Qโ‚™: **{Qn:.2f} mยณ/s** \n"
154
- f" (์ €์œ ๋Ÿ‰ ์ž„๊ณ„ **{q_low:.2f}**, ๊ณ ์œ ๋Ÿ‰ ์ž„๊ณ„ **{q_high:.2f}**)")
155
- md.append("")
156
- md.append("### ๊ถŒ์žฅ ๋™์ž‘")
157
- for i, a in enumerate(actions, 1):
158
- md.append(f"{i}. {a}")
159
- md.append("")
160
- md.append("### ์ถ”์ •/์„ค์ • ๊ฐ’")
161
- for k, v in estimates.items():
162
- md.append(f"- **{k}**: {v}")
163
- md.append("")
164
- md.append("> ์ฐธ๊ณ : ์ถœ๋ ฅ ์ถ”์ •์€ ๊ฐ„์ด ํšจ์œจ๊ณก์„ /์ปคํ…Œ์ผ ๋ฐ˜์˜์œผ๋กœ ์‚ฐ์ •๋œ ๋ณด์ˆ˜์น˜์ž…๋‹ˆ๋‹ค.")
165
- return "\n".join(md)
166
-
167
- # ---------------------------
168
- # Gradio UI
169
- # ---------------------------
170
- with gr.Blocks(theme=gr.themes.Soft()) as app:
171
- gr.Markdown("## ๐ŸŒŠ ์†Œ์ˆ˜๋ ฅ 4-๋ชจ๋“œ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (Hugging Face Spaces)")
172
  with gr.Row():
173
  Q_in = gr.Number(label="ํ˜„์žฌ ์œ ๋Ÿ‰ Q (mยณ/s)", value=3.0)
174
  rain = gr.Number(label="๊ฐ•์šฐ ์˜ˆ๋ณด (mm/24h)", value=0)
175
- dp = gr.Number(label="ํŠธ๋ž˜์‹œ๋ž™ ์ฐจ์•• ฮ”P (kPa)", value=0)
176
  emer = gr.Checkbox(label="๋น„์ƒ ์•Œ๋žŒ (Emergency)", value=False)
177
-
178
  with gr.Accordion("๊ณ ๊ธ‰ ์„ค์ • (์„ค๊ณ„/์ž„๊ณ„๊ฐ’)", open=False):
179
  with gr.Row():
180
- Hn = gr.Number(label="์„ค๊ณ„ ๋‚™์ฐจ Hโ‚™ (m)", value=8.0)
181
- Qn = gr.Number(label="์„ค๊ณ„ ์œ ๋Ÿ‰ Qโ‚™ (mยณ/s)", value=3.5)
182
  with gr.Row():
183
  rain_thr = gr.Number(label="ํ™์ˆ˜ ํŒ๋‹จ ๊ฐ•์šฐ ์ž„๊ณ„ (mm/24h)", value=40.0)
184
  dp_limit = gr.Number(label="ํŠธ๋ž˜์‹œ๋ž™ ฮ”P ์ž„๊ณ„ (kPa)", value=3.0)
185
 
186
- run_btn = gr.Button("์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์‹คํ–‰", variant="primary")
187
- out_md = gr.Markdown()
188
-
189
- run_btn.click(
190
- fn=run_sim,
191
- inputs=[Q_in, rain, dp, emer, Hn, Qn, rain_thr, dp_limit],
192
- outputs=out_md
193
- )
194
 
195
- # Spaces์—์„œ๋Š” launch() ํ˜ธ์ถœ ๋ถˆํ•„์š”ํ•˜์ง€๋งŒ, ๋กœ์ปฌ ํ…Œ์ŠคํŠธ์—์„  ์•„๋ž˜ ์ฃผ์„ ํ•ด์ œ
196
- # if __name__ == "__main__":
197
- # app.launch()
 
1
  import gradio as gr
2
 
3
+ # ========== ๊ณ„์‚ฐ ๋กœ์ง ==========
4
+ RHO = 1000.0
5
+ G = 9.80665
6
+ PF_TARGET = 0.98
7
 
 
 
 
 
 
8
  def efficiency_from_relative_flow(r: float) -> float:
9
  r = max(0.0, min(1.2, r))
10
+ curve = [(0.0,0.0),(0.1,0.4),(0.3,0.6),(0.5,0.75),(0.7,0.85),
11
+ (0.9,0.90),(1.0,0.91),(1.2,0.88)]
12
+ for (x1,y1),(x2,y2) in zip(curve[:-1], curve[1:]):
 
 
 
 
 
 
 
 
13
  if x1 <= r <= x2:
14
+ t = 0.0 if x2 == x1 else (r-x1)/(x2-x1)
15
+ return y1 + t*(y2-y1)
16
  return 0.0
17
 
18
+ def electrical_power_kw(Q_in, head_m, eta):
 
19
  return (RHO * G * Q_in * head_m * max(0.0, min(1.0, eta))) / 1000.0
20
 
21
+ def decide_mode(Q_in, q_low, q_high, rain_mm, dp_kpa, rain_thr, dp_limit, emergency):
 
22
  if emergency:
23
  return "Emergency"
24
  if Q_in < q_low:
 
27
  return "Flood"
28
  return "Normal"
29
 
30
+ def run_sim(Q_in, rain_mm, dp_kpa, emergency, Hn, Qn, rain_thr, dp_limit):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  try:
32
  Q_in = float(Q_in)
33
  rain_mm = float(rain_mm)
 
44
  q_high = 1.2 * Qn
45
 
46
  mode = decide_mode(Q_in, q_low, q_high, rain_mm, dp_kpa, rain_thr, dp_limit, emergency)
47
+ r = min(Q_in, Qn) / Qn if Qn > 0 else 0.0
48
+ eta = efficiency_from_relative_flow(r)
49
+ p_kw = electrical_power_kw(min(Q_in, Qn), Hn, eta)
50
+
51
+ lines = []
52
+ lines.append(f"## ์šด์ „ ๋ชจ๋“œ: **{mode}**")
53
+ lines.append("")
54
+ lines.append("### ์ž…๋ ฅ ์š”์•ฝ")
55
+ lines.append(f"- ์œ ๋Ÿ‰ Q: **{Q_in:.2f} mยณ/s**")
56
+ lines.append(f"- ๊ฐ•์šฐ ์˜ˆ๋ณด: **{rain_mm:.1f} mm/24h**")
57
+ lines.append(f"- ํŠธ๋ž˜์‹œ๋ž™ ฮ”P: **{dp_kpa:.1f} kPa**")
58
+ lines.append(f"- ์„ค๊ณ„ ๋‚™์ฐจ Hโ‚™: **{Hn:.2f} m**, ์„ค๊ณ„ ์œ ๋Ÿ‰ Qโ‚™: **{Qn:.2f} mยณ/s** ")
59
+ lines.append(f" (์ €์œ ๋Ÿ‰ ์ž„๊ณ„ **{q_low:.2f}**, ๊ณ ์œ ๋Ÿ‰ ์ž„๊ณ„ **{q_high:.2f}**)")
60
+ lines.append("")
61
+ lines.append("### ์ถ”์ •/์„ค์ • ๊ฐ’")
62
+ lines.append(f"- **ํšจ์œจ(eta)**: {eta:.3f}")
63
+ lines.append(f"- **์ถ”์ • ์ถœ๋ ฅ(kW)**: {p_kw:.1f}")
64
+ lines.append(f"- **ESS ์—ญ๋ฅ  ๋ชฉํ‘œ**: {PF_TARGET}")
65
+ return "\n".join(lines)
66
+
67
+ # ========== Gradio UI ==========
68
+ with gr.Blocks(title="Small-Hydro 4-Mode Simulator") as demo:
69
+ gr.Markdown("## ๐ŸŒŠ ์†Œ์ˆ˜๋ ฅ 4-๋ชจ๋“œ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (Spaces)")
 
 
 
 
 
 
70
  with gr.Row():
71
  Q_in = gr.Number(label="ํ˜„์žฌ ์œ ๋Ÿ‰ Q (mยณ/s)", value=3.0)
72
  rain = gr.Number(label="๊ฐ•์šฐ ์˜ˆ๋ณด (mm/24h)", value=0)
73
+ dp = gr.Number(label="ํŠธ๋ž˜์‹œ๋ž™ ฮ”P (kPa)", value=0)
74
  emer = gr.Checkbox(label="๋น„์ƒ ์•Œ๋žŒ (Emergency)", value=False)
 
75
  with gr.Accordion("๊ณ ๊ธ‰ ์„ค์ • (์„ค๊ณ„/์ž„๊ณ„๊ฐ’)", open=False):
76
  with gr.Row():
77
+ Hn = gr.Number(label="์„ค๊ณ„ ๋‚™์ฐจ Hโ‚™ (m)", value=8.0)
78
+ Qn = gr.Number(label="์„ค๊ณ„ ์œ ๋Ÿ‰ Qโ‚™ (mยณ/s)", value=3.5)
79
  with gr.Row():
80
  rain_thr = gr.Number(label="ํ™์ˆ˜ ํŒ๋‹จ ๊ฐ•์šฐ ์ž„๊ณ„ (mm/24h)", value=40.0)
81
  dp_limit = gr.Number(label="ํŠธ๋ž˜์‹œ๋ž™ ฮ”P ์ž„๊ณ„ (kPa)", value=3.0)
82
 
83
+ btn = gr.Button("์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์‹คํ–‰", variant="primary")
84
+ out = gr.Markdown()
85
+ btn.click(run_sim, [Q_in, rain, dp, emer, Hn, Qn, rain_thr, dp_limit], out)
 
 
 
 
 
86
 
87
+ # Spaces์—์„œ๋Š” launch๋ฅผ ํ˜ธ์ถœํ•ด๋„ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.
88
+ if __name__ == "__main__":
89
+ demo.launch()