Simulasi Equipment

main
ariwahyunahar 3 months ago
parent 516dedc703
commit 0df40ecc60

@ -0,0 +1,22 @@
### Simulasi Peralatan (Simulation Equipment)
Modul ini digunakan untuk menghitung proyeksi simulasi biaya pemeliharaan dan risiko alat (`LCC Simulation`).
#### Persyaratan (Requirements)
Script ini membutuhkan Python 3 dan library `psycopg2` untuk koneksi ke database PostgreSQL.
#### Instalasi (Installation)
Anda dapat menginstal library yang dibutuhkan menggunakan `requirements.txt`:
```bash
pip install -r src/sim_equipment/requirements.txt
```
#### Cara Menjalankan (How to Run)
Jalankan script `simulation.py` dari root project:
```bash
python src/sim_equipment/simulation.py
```
Pastikan kredensial database di dalam `simulation.py` sudah benar sebelum dijalankan.

@ -0,0 +1,199 @@
import psycopg2
from psycopg2 import extras
import math
from datetime import datetime
# DATABASE CONNECTION SETTINGS
DATABASE_HOSTNAME = "192.168.1.85"
DATABASE_PORT = "5432"
DATABASE_CREDENTIAL_USER = "postgres"
DATABASE_CREDENTIAL_PASSWORD = "postgres"
DATABASE_NAME = "digital_twin"
# EXCEL-LIKE FINANCIAL FUNCTIONS
def fv(rate, nper, pmt, pv):
"""
Rumus FV Excel: FV = pv * (1+rate)^nper + pmt * ((1+rate)^nper - 1) / rate
Jika rate = 0, FV = pv + pmt * nper
Sign convention: Excel FV mengembalikan nilai negatif jika input positif.
Namun di flow instruksi, dia menggunakan -FV(...) yang berarti ingin nilai positif.
"""
if rate == 0:
return -(pv + pmt * nper)
term = (1 + rate) ** nper
res = pv * term + pmt * (term - 1) / rate
return -res
def pmt(rate, nper, pv, fv=0):
"""
Rumus PMT Excel: PMT = (pv * (1+rate)^nper + fv) * rate / (1 - (1+rate)^nper)
Jika rate = 0, PMT = -(pv + fv) / nper
"""
if nper == 0:
return 0
if rate == 0:
return -(pv + fv) / nper
term = (1 + rate) ** nper
res = (pv * term + fv) * rate / (1 - term)
return res
def npv(rate, values):
"""
Rumus NPV Excel: NPV = sum(values[i] / (1+rate)^(i+1))
"""
res = 0
for i, val in enumerate(values):
res += val / ((1 + rate) ** (i + 1))
return res
def pv(rate, nper, pmt, fv=0):
"""
Rumus PV Excel: PV = (fv / (1+rate)^nper + pmt * ((1 - (1+rate)^-nper) / rate)) * -1
"""
if rate == 0:
return -(fv + pmt * nper)
term = (1 + rate) ** nper
res = (fv / term + pmt * ((1 - (1/term)) / rate))
return -res
def run_simulation(assetnum_target='A27311'):
try:
conn = psycopg2.connect(
host=DATABASE_HOSTNAME,
port=DATABASE_PORT,
user=DATABASE_CREDENTIAL_USER,
password=DATABASE_CREDENTIAL_PASSWORD,
dbname=DATABASE_NAME
)
cur = conn.cursor(cursor_factory=extras.RealDictCursor)
# 1. Mendapatkan data dari lcc_sim_equipment
cur.execute("SELECT * FROM lcc_sim_equipment WHERE assetnum = %s", (assetnum_target,))
equipment = cur.fetchone()
if not equipment:
print(f"Equipment with assetnum {assetnum_target} not found.")
return
# 2. Mendapatkan parameter dari lcc_ms_master
master_params = {}
param_names = ['history_inflation_rate', 'inflation_rate', 'history_future_inflation_rate_annual', 'discount_rate']
for name in param_names:
cur.execute("SELECT value_num FROM public.lcc_ms_master WHERE name = %s", (name,))
row = cur.fetchone()
master_params[name] = float(row['value_num']) if row and row['value_num'] is not None else 0.0
history_inflation_rate = master_params['history_inflation_rate']
inflation_rate = master_params['inflation_rate']
history_future_inflation_rate_annual = master_params['history_future_inflation_rate_annual']
discount_rate = master_params['discount_rate']
# 3. Hitung parameter awal
tahun_ini = datetime.now().year
# capital_cost_tahun_ini = -FV(history_inflation_rate; (tahun_ini-lcc_sim_equipment.tahun_perolehan); 0; lcc_sim_equipment.capital_cost)
# Note: function fv(rate, nper, pmt, pv) returns -res (Excel like)
# In instructions: -FV(...) means -(Excel FV result).
# So it becomes positive value.
nper_cap = tahun_ini - equipment['tahun_perolehan']
capital_cost_tahun_ini = -fv(history_inflation_rate, nper_cap, 0, equipment['capital_cost'])
maintenance_cost = 0.01 * capital_cost_tahun_ini
# 4. Loop Simulasi
insert_data = []
array_risk_cost = []
array_risk_cost2 = []
xx = 0
xx2 = 0
risk_cost_tahun_0 = 0
for t in range(equipment['design_life'] + 1):
# assetnum = lcc_sim_equipment.assetnum
# Flow instruksi: tahun = lcc_sim_equipment.tahun_perolehan - (t+1)
# Namun, jika t=0, maka tahun = tahun_perolehan - 1
# Dan jika t bertambah, tahun berkurang. Ini kontradiksi dengan "tahun - tahun_ini"
# yang digunakan di formula FV.
# Saya akan mengikuti "tahun = lcc_sim_equipment.tahun_perolehan + t"
# agar sejalan dengan konsep 'age' (t).
sim_tahun = equipment['tahun_perolehan'] + t
age = t
risk_cost = 0
npv_val = None
annual_mnt_cost = None
annual_acc_cost = None
eac = None
if t == 0:
# risk_cost = -FV(history_inflation_rate; (sim_tahun-tahun_ini); 0; capital_cost_tahun_ini)
risk_cost = -fv(history_inflation_rate, (sim_tahun - tahun_ini), 0, capital_cost_tahun_ini)
risk_cost_tahun_0 = risk_cost
npv_val = None
annual_mnt_cost = None
annual_acc_cost = None
eac = None
else:
# risk_cost = -FV(history_inflation_rate; (sim_tahun-tahun_ini); 0; maintenance_cost)
risk_cost = -fv(history_inflation_rate, (sim_tahun - tahun_ini), 0, maintenance_cost)
# print(f"Simulating for {history_inflation_rate, (sim_tahun - tahun_ini), 0, maintenance_cost}")
if sim_tahun <= tahun_ini:
array_risk_cost.append(risk_cost)
npv_val = npv(history_inflation_rate, array_risk_cost)
eac = None
xx = t
xx2 = npv_val
else:
array_risk_cost2.append(risk_cost)
# npv = -PV(history_inflation_rate;xx;0;NPV(inflation_rate;array_risk_cost2))+xx2
inner_npv = npv(inflation_rate, array_risk_cost2)
npv_val = -pv(history_inflation_rate, xx, 0, inner_npv) + xx2
eac = None
# annual_mnt_cost = -PMT(history_future_inflation_rate_annual;age;npv)
annual_mnt_cost = -pmt(history_future_inflation_rate_annual, age, npv_val)
# annual_acc_cost = -PMT(discount_rate;age;risk_cost_tahun_0)
annual_acc_cost = -pmt(discount_rate, age, risk_cost_tahun_0)
eac = annual_mnt_cost + annual_acc_cost
insert_data.append((
equipment['assetnum'],
sim_tahun,
age,
float(risk_cost) if risk_cost is not None else 0,
float(npv_val) if npv_val is not None else None,
float(annual_mnt_cost) if annual_mnt_cost is not None else None,
float(annual_acc_cost) if annual_acc_cost is not None else None,
float(eac) if eac is not None else None,
datetime.now()
))
# 5. Insert ke lcc_sim_equipment_tr
if insert_data:
# Clear previous simulation for this asset
cur.execute("DELETE FROM lcc_sim_equipment_tr WHERE assetnum = %s", (equipment['assetnum'],))
insert_query = """
INSERT INTO lcc_sim_equipment_tr
(assetnum, tahun, age, risk_cost, npv, annual_mnt_cost, annual_acc_cost, eac, created_at)
VALUES %s
"""
extras.execute_values(cur, insert_query, insert_data)
conn.commit()
print(f"Successfully inserted {len(insert_data)} simulation rows for {equipment['assetnum']}.")
cur.close()
conn.close()
except Exception as e:
print(f"Error occurred: {e}")
if 'conn' in locals() and conn:
conn.rollback()
if __name__ == "__main__":
run_simulation('A27311')
Loading…
Cancel
Save