SHELLAPANDIANGANHUNGING commited on
Commit
5d47d60
·
verified ·
1 Parent(s): 513a2b0

Create calculator.py

Browse files
Files changed (1) hide show
  1. calculator.py +379 -0
calculator.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import plotly.graph_objects as go
5
+ from datetime import datetime
6
+
7
+ if 'submitted' not in st.session_state:
8
+ st.session_state.submitted = False
9
+
10
+ st.set_page_config(page_title="Blowby Pressure & Fuel Impact Dashboard", layout="wide")
11
+
12
+
13
+ st.markdown("""
14
+ <style>
15
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
16
+
17
+ .main {
18
+ background: linear-gradient(135deg, #1a2a44 0%, #2c3e50 100%);
19
+ font-family: 'Poppins', sans-serif;
20
+ color: #ecf0f1;
21
+ padding: 20px;
22
+ }
23
+ .stButton>button {
24
+ background: linear-gradient(90deg, #f1c40f, #e67e22);
25
+ color: #1a2a44;
26
+ border: none;
27
+ border-radius: 25px;
28
+ padding: 12px 30px;
29
+ font-weight: 600;
30
+ transition: all 0.3s ease;
31
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
32
+ }
33
+ .stButton>button:hover {
34
+ background: linear-gradient(90deg, #e67e22, #f1c40f);
35
+ transform: translateY(-2px);
36
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
37
+ }
38
+ .stRadio>div>label {
39
+ font-size: 16px;
40
+ color: #ecf0f1;
41
+ background-color: rgba(255, 255, 255, 0.1);
42
+ padding: 8px 15px;
43
+ border-radius: 15px;
44
+ transition: all 0.3s ease;
45
+ }
46
+ .stRadio>div>label:hover {
47
+ background-color: rgba(255, 255, 255, 0.2);
48
+ }
49
+ .metric-card {
50
+ background: rgba(255, 255, 255, 0.95);
51
+ padding: 20px;
52
+ border-radius: 15px;
53
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
54
+ margin-bottom: 20px;
55
+ transition: transform 0.3s ease;
56
+ }
57
+ .metric-card:hover {
58
+ transform: translateY(-5px);
59
+ }
60
+ h1 {
61
+ color: #f1c40f;
62
+ font-weight: 700;
63
+ text-align: center;
64
+ font-size: 2.5em;
65
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
66
+ }
67
+ h2 {
68
+ color: #ecf0f1;
69
+ font-weight: 600;
70
+ font-size: 1.8em;
71
+ margin-bottom: 15px;
72
+ }
73
+ .stSelectbox {
74
+ background-color: rgba(255, 255, 255, 0.1);
75
+ border-radius: 10px;
76
+ padding: 5px;
77
+ }
78
+ .stSlider>div>div>div {
79
+ background-color: #f1c40f !important;
80
+ }
81
+ .stNumberInput input {
82
+ background-color: rgba(255, 255, 255, 0.1);
83
+ color: #ecf0f1;
84
+ border-radius: 10px;
85
+ border: 1px solid #f1c40f;
86
+ }
87
+ .thank-you-message {
88
+ display: flex;
89
+ justify-content: center;
90
+ align-items: center;
91
+ height: 80vh;
92
+ font-size: 2.5em;
93
+ font-weight: 600;
94
+ color: #f1c40f;
95
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
96
+ }
97
+ </style>
98
+ """, unsafe_allow_html=True)
99
+
100
+
101
+ def show_thank_you_message():
102
+ st.markdown("""
103
+ <div class="thank-you-message">
104
+ Terimakasih sudah simulasi
105
+ </div>
106
+ """, unsafe_allow_html=True)
107
+
108
+
109
+ if st.session_state.submitted:
110
+ show_thank_you_message()
111
+ else:
112
+
113
+ with st.sidebar:
114
+ st.markdown("<h2 style='color: #f1c40f;'>⚙️ Dashboard Controls</h2>", unsafe_allow_html=True)
115
+ st.markdown("**Developed by: Bukit Technology (RnD)**")
116
+ st.markdown(f"**Last Updated:** {datetime.now().strftime('%Y-%m-%d')}")
117
+ st.markdown("---")
118
+ st.markdown("Use this calculator to analyze blowby pressure and fuel impact for strategic decisions.")
119
+
120
+
121
+ col_logo, col_title = st.columns([1, 4])
122
+ with col_logo:
123
+ try:
124
+ st.image("buma ina.PNG", width=150)
125
+ except FileNotFoundError:
126
+ st.warning("⚠️ File logo 'buma_ina.PNG' tidak ditemukan. Silakan pastikan file ada di direktori yang sama dengan script.")
127
+ with col_title:
128
+ st.title("Calculator CHA for Fuel Rate Impact")
129
+ # st.markdown("**Analisis Blowby Pressure & Fuel Impact untuk Pengambilan Keputusan Strategis**")
130
+
131
+
132
+ try:
133
+ detail = pd.read_csv('1_DEV_SUMMARY_detail_data_HD785_7_ENGINE_last3month.csv')
134
+ except FileNotFoundError:
135
+ st.error("❌ File '1_DEV_SUMMARY_detail_data_HD785_7_ENGINE_last3month.csv' tidak ditemukan.")
136
+ st.stop()
137
+
138
+
139
+ st.subheader("🔍 Pilih Unit untuk Analisis")
140
+ unit_list = sorted(detail['equipment_no'].dropna().unique())
141
+ selected_unit = st.selectbox("Pilih unit number yang akan disimulasikan:", unit_list, help="Pilih nomor peralatan untuk analisis")
142
+
143
+ unit_df = detail[detail['equipment_no'] == selected_unit].sort_values("comp_life")
144
+ if unit_df.empty:
145
+ st.warning("⚠️ Data tidak tersedia untuk unit ini.")
146
+ st.stop()
147
+
148
+
149
+ current_life_df = (
150
+ detail[detail['solving_algorithm'].notna()]
151
+ .sort_values(['equipment_no', 'comp_life'])
152
+ .groupby('equipment_no')
153
+ .tail(1)
154
+ )
155
+ if selected_unit not in current_life_df['equipment_no'].values:
156
+ st.error("❌ Data current component life tidak tersedia untuk unit ini.")
157
+ st.stop()
158
+ current_life = current_life_df.loc[current_life_df['equipment_no'] == selected_unit, 'comp_life'].iloc[0]
159
+
160
+ col1, col2 = st.columns([2, 1])
161
+
162
+ with col1:
163
+
164
+ st.subheader("📊 Grafik Blowby Pressure terhadap Umur Komponen")
165
+ max_life = unit_df['comp_life'].max()
166
+ fig = px.line(unit_df, x='comp_life', y='blowby_press_max_act',
167
+ title=f"Unit: {selected_unit}",
168
+ labels={'comp_life': 'Component Life (Hours)', 'blowby_press_max_act': 'Pressure (mmH2O)'},
169
+ line_shape='linear', render_mode='svg')
170
+ fig.add_vline(x=current_life, line_dash="dash", line_color="#7f8c8d", annotation_text="Current Life", annotation_position="top left")
171
+ fig.update_traces(line_color='#1abc9c', line_width=3, marker=dict(size=8))
172
+ fig.update_layout(
173
+ plot_bgcolor='rgba(0,0,0,0)',
174
+ paper_bgcolor='rgba(0,0,0,0)',
175
+ font=dict(family="Poppins", size=12, color="#ecf0f1"),
176
+ title_font=dict(size=18, color="#f1c40f"),
177
+ showlegend=True,
178
+ xaxis=dict(showgrid=True, gridcolor='rgba(255,255,255,0.2)'),
179
+ yaxis=dict(showgrid=True, gridcolor='rgba(255,255,255,0.2)')
180
+ )
181
+ st.plotly_chart(fig, use_container_width=True)
182
+
183
+ with col2:
184
+
185
+ st.subheader("⏳ Current Component Life")
186
+ st.markdown(f"""
187
+ <div class="metric-card">
188
+ <h3 style="color: #f1c40f;">Current Life</h3>
189
+ <p style="font-size: 24px; color: #1abc9c; font-weight: bold;">{current_life:,.0f} jam</p>
190
+ </div>
191
+ """, unsafe_allow_html=True)
192
+
193
+
194
+ st.subheader("⚙️ Simulasi Perpanjangan Umur Komponen")
195
+ input_method = st.radio("Pilih metode input:", ["Slider", "Input Numerik"], horizontal=True)
196
+
197
+
198
+ max_deviation = int(max_life - current_life)
199
+
200
+ if input_method == "Slider":
201
+ extended_life = st.slider(
202
+ "Simulasikan Perpanjangan Umur Komponen Hingga (jam):",
203
+ min_value=int(current_life + 100),
204
+ max_value=int(max_life),
205
+ value=int(min(current_life + 1000, max_life)),
206
+ step=100,
207
+ help="Geser untuk memilih umur komponen yang diinginkan"
208
+ )
209
+ deviation = extended_life - current_life
210
+ else:
211
+ deviation = st.number_input(
212
+ "Masukkan Perpanjangan Umur Komponen Sebesar (jam):",
213
+ min_value=100,
214
+ max_value=max_deviation,
215
+ value=min(1000, max_deviation),
216
+ step=100,
217
+ help="Masukkan jumlah jam perpanjangan dari current life"
218
+ )
219
+ extended_life = current_life + deviation
220
+
221
+
222
+ st.markdown(f"**Umur Komponen Diperpanjang Hingga:** {extended_life:,.0f} jam (Perpanjangan: {deviation:,.0f} jam)", unsafe_allow_html=True)
223
+
224
+
225
+ sim_df = unit_df[(unit_df['comp_life'] > current_life) & (unit_df['comp_life'] <= extended_life)]
226
+
227
+ def hitung_avg_blowby(df, batas):
228
+ tmp = df[['comp_life', 'blowby_press_max_act']].dropna().sort_values('comp_life')
229
+ tmp = tmp[tmp['comp_life'] <= batas]
230
+ if tmp.empty:
231
+ return 0
232
+ tail = tmp.tail(10)
233
+ if len(tail) < 10:
234
+ st.warning(f"Hanya {len(tail)} titik data (<= {batas} jam).")
235
+ return tail['blowby_press_max_act'].mean()
236
+
237
+ def hitung_avg_blowbyawal(df, batas):
238
+ tmp = df[['comp_life', 'blowby_press_max_act']].dropna().sort_values('comp_life')
239
+ tmp = tmp[tmp['comp_life'] <= batas]
240
+ if tmp.empty:
241
+ return 0
242
+ tail = tmp.tail(30)
243
+ if len(tail) < 30:
244
+ st.warning(f"Hanya {len(tail)} titik data (<= {batas} jam).")
245
+ return tail['blowby_press_max_act'].mean()
246
+
247
+ def fuel_awal_data(df, batas):
248
+ tmp = df[['comp_life', 'fuel_rate_act']].dropna().sort_values('comp_life')
249
+ tmp = tmp[tmp['comp_life'] <= batas]
250
+ if tmp.empty:
251
+ return 0
252
+ tail = tmp.tail(5)
253
+ if len(tail) < 5:
254
+ st.warning(f"Hanya {len(tail)} titik data (<= {batas} jam).")
255
+ return tail['fuel_rate_act'].mean()
256
+
257
+ st.subheader("⛽ Prediksi Fuel Rate")
258
+ avg_blowby_awal = fuel_awal_data(unit_df, current_life)
259
+ avg_blowby_akhir = hitung_avg_blowby(unit_df, extended_life)
260
+ delta_life = extended_life - current_life
261
+ fuel_rate_awal = (avg_blowby_awal * 0.004) + 71.86 # L/h
262
+ fuel_rate_akhir = (avg_blowby_akhir * 0.004) + 71.86 # L/h
263
+
264
+ hours_ext = extended_life - current_life
265
+ fuel_usage = fuel_rate_akhir * hours_ext # total L over extension
266
+
267
+ col3, col4, col5 = st.columns(3)
268
+ with col3:
269
+ st.markdown(f"""
270
+ <div class="metric-card">
271
+ <h4 style="color: #34495e;">Fuel Rate Terakhir</h4>
272
+ <p style="font-size: 20px; color: #3498db;">{fuel_rate_awal:.2f} L/h</p>
273
+ </div>
274
+ """, unsafe_allow_html=True)
275
+ with col4:
276
+ st.markdown(f"""
277
+ <div class="metric-card">
278
+ <h4 style="color: #34495e;">Fuel Rate Akumulasi</h4>
279
+ <p style="font-size: 20px; color: #3498db;">{(fuel_rate_akhir * delta_life):,.2f} L</p>
280
+ </div>
281
+ """, unsafe_allow_html=True)
282
+ with col5:
283
+ st.markdown(f"""
284
+ <div class="metric-card">
285
+ <h4 style="color: #34495e;">Total Extend</h4>
286
+ <p style="font-size: 20px; color: #3498db;">{delta_life:,.2f} Hm</p>
287
+ </div>
288
+ """, unsafe_allow_html=True)
289
+
290
+ if not sim_df.empty and sim_df['trendline_blow'].notna().any():
291
+ last_f = sim_df['trendline_blow'].dropna().iloc[-1]
292
+ fr_f = last_f * 0.004 + 71.86
293
+ rpm_f = last_f * 0.034 + 1303.75
294
+ col6, col7 = st.columns(2)
295
+ with col6:
296
+ st.markdown(f"""
297
+ <div class="metric-card">
298
+ <h4 style="color: #34495e;">Fuel Rate Forecast</h4>
299
+ <p style="font-size: 20px; color: #e67e22;">{fr_f:.2f} L/h</p>
300
+ </div>
301
+ """, unsafe_allow_html=True)
302
+ with col7:
303
+ st.markdown(f"""
304
+ <div class="metric-card">
305
+ <h4 style="color: #34495e;">Engine Speed Forecast</h4>
306
+ <p style="font-size: 20px; color: #e67e22;">{rpm_f:.2f} RPM</p>
307
+ </div>
308
+ """, unsafe_allow_html=True)
309
+
310
+
311
+ st.subheader("💰 Analisis Keuntungan dan Kerugian")
312
+ harga_engine = 110_000 # USD
313
+ harga_fuel = 0.8 # USD/L
314
+
315
+ cost_per_h = harga_engine / 25_000
316
+ saving = cost_per_h * delta_life
317
+ fuel_cost = fuel_usage * harga_fuel
318
+ net_savings = fuel_cost - saving
319
+
320
+ col8, col9, col10 = st.columns(3)
321
+ with col8:
322
+ st.markdown(f"""
323
+ <div class="metric-card">
324
+ <h4 style="color: #34495e;">Cost Replacement</h4>
325
+ <p style="font-size: 20px; color: #2ecc71;">USD {saving:,.2f}</p>
326
+ </div>
327
+ """, unsafe_allow_html=True)
328
+ with col9:
329
+ st.markdown(f"""
330
+ <div class="metric-card">
331
+ <h4 style="color: #34495e;">Cost Fuel (Extend)</h4>
332
+ <p style="font-size: 20px; color: #e74c3c;">USD {fuel_cost:,.2f}</p>
333
+ </div>
334
+ """, unsafe_allow_html=True)
335
+ with col10:
336
+ st.markdown(f"""
337
+ <div class="metric-card">
338
+ <h4 style="color: #34495e;">Net Savings</h4>
339
+ <p style="font-size: 20px; color: #9b59b6;">USD {net_savings:,.2f}</p>
340
+ </div>
341
+ """, unsafe_allow_html=True)
342
+
343
+ st.subheader("Perbandingan Penghematan vs Biaya Fuel")
344
+ fig2 = go.Figure()
345
+ fig2.add_trace(go.Bar(
346
+ x=[saving, fuel_cost],
347
+ y=["Replacement Cost", "Fuel Cost if Extend"],
348
+ orientation='h',
349
+ marker=dict(color=['#2ecc71', '#e74c3c']),
350
+ text=[f"USD {saving:,.2f}", f"USD {fuel_cost:,.2f}"],
351
+ textposition='auto'
352
+ ))
353
+ fig2.update_layout(
354
+ title="Perbandingan Biaya",
355
+ title_font=dict(size=18, color="#f1c40f"),
356
+ plot_bgcolor='rgba(0,0,0,0)',
357
+ paper_bgcolor='rgba(0,0,0,0)',
358
+ font=dict(family="Poppins", size=12, color="#ecf0f1"),
359
+ showlegend=False,
360
+ xaxis=dict(showgrid=True, gridcolor='rgba(255,255,255,0.2)'),
361
+ yaxis=dict(showgrid=False)
362
+ )
363
+ st.plotly_chart(fig2, use_container_width=True)
364
+
365
+
366
+ st.subheader("🔄 Opsi Tindakan")
367
+ choice = st.radio("Pilih tindakan:", ["replacement/service", "extend component"], horizontal=True)
368
+ if choice == "replacement/service":
369
+ st.success("✅ Anda memilih untuk replacement component.")
370
+ else:
371
+ st.error("❌ Anda memilih untuk extend component.")
372
+
373
+
374
+ if st.button("Submit"):
375
+ st.session_state.submitted = True
376
+ st.rerun() # Mengganti st.experimental_rerun() dengan st.rerun()
377
+
378
+ st.markdown("---")
379
+ st.markdown("<p style='text-align: center; color: #ecf0f1;'>© 2025 Your Company. All Rights Reserved.</p>", unsafe_allow_html=True)