Skip to content

Commit 82fbc4b

Browse files
authored
Update calculator.py
1 parent 57c11b2 commit 82fbc4b

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

calculator.py

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
def calculate_5yr_tco(config, user_inputs):
55
"""
6-
Calculates 5-year TCO with correct initial CAPEX reporting.
7-
초기 CAPEX 보고 로직이 수정된 버전입니다.
6+
Calculates 5-year TCO with detailed cost breakdowns for CAPEX and OPEX.
7+
CAPEX와 OPEX에 대한 상세 비용 내역을 포함하여 5년 TCO를 계산합니다.
88
"""
99
demand_profile = user_inputs['demand_profile']
1010
energy_mix = user_inputs['energy_mix']
@@ -15,7 +15,7 @@ def calculate_5yr_tco(config, user_inputs):
1515
asset_lifetime = config.get('asset_lifetime_years', 20)
1616
discount_rate = econ_assumptions['discount_rate']
1717

18-
# --- 1. Calculate Initial CAPEX (at t=0) ---
18+
# --- 1. Calculate Initial CAPEX (at t=0) and details ---
1919
initial_capex = 0
2020
capex_details = {}
2121
peak_demand_kw_yr1 = demand_profile['peak_demand_mw'].iloc[0] * 1000
@@ -27,8 +27,9 @@ def calculate_5yr_tco(config, user_inputs):
2727
capex_details[f"{source}_capex"] = capex
2828
initial_capex += capex
2929

30-
# --- 2. Calculate PV of all costs over the simulation period ---
30+
# --- 2. Initialize variables for loop ---
3131
results = []
32+
opex_breakdown_pv = {}
3233
total_opex_pv = 0
3334
total_replacement_capex_pv = 0
3435
total_demand_pv_kwh = 0
@@ -43,7 +44,7 @@ def calculate_5yr_tco(config, user_inputs):
4344
annual_capex_replacement = 0
4445
fc_params = tech_params.get('hydrogen_SOFC', {})
4546
stack_lifetime = fc_params.get('stack_lifetime_years', 4)
46-
if (simulation_year - 1) > 0 and (simulation_year - 1) % stack_lifetime == 0 and energy_mix.get('hydrogen_SOFC', 0) > 0:
47+
if simulation_year > 1 and (simulation_year - 1) % stack_lifetime == 0 and energy_mix.get('hydrogen_SOFC', 0) > 0:
4748
fc_capacity_kw = peak_demand_kw_yr1 * (energy_mix['hydrogen_SOFC'] / 100)
4849
replacement_rate = fc_params.get('stack_replacement_cost_rate', 0.4)
4950
replacement_cost = (fc_capacity_kw * fc_params.get('capex_per_kw', 0)) * replacement_rate
@@ -52,61 +53,67 @@ def calculate_5yr_tco(config, user_inputs):
5253

5354
total_replacement_capex_pv += annual_capex_replacement * discount_factor
5455

55-
# Annual OPEX
56-
# ... (OPEX calculation logic remains the same)
57-
annual_opex = 0
58-
total_emissions_kg = 0
56+
# Annual OPEX Calculation
57+
opex_details_annual = {}
5958
initial_grid_price = scenario_params.get('grid_price_per_kwh', 0.12)
6059
initial_ng_price = scenario_params.get('gas_fuel_cost_per_kwh', 0.08)
60+
6161
grid_kwh = annual_demand_kwh * (energy_mix.get('grid', 0) / 100)
62-
grid_price = initial_grid_price * ((1 + econ_assumptions['grid_escalation']) ** (simulation_year - 1))
63-
annual_opex += grid_kwh * grid_price
64-
total_emissions_kg += grid_kwh * tech_params.get('grid', {}).get('carbon_emission_factor', 0)
62+
opex_details_annual['grid_purchase_cost'] = grid_kwh * (initial_grid_price * ((1 + econ_assumptions['grid_escalation']) ** (simulation_year - 1)))
63+
64+
total_emissions_kg = grid_kwh * tech_params.get('grid', {}).get('carbon_emission_factor', 0)
65+
66+
opex_details_annual['o&m_cost'] = 0
67+
opex_details_annual['h2_fuel_cost'] = 0
68+
opex_details_annual['ng_fuel_cost'] = 0
69+
6570
for source in ['solar', 'wind', 'hydrogen_SOFC', 'NG_SOFC']:
6671
if energy_mix.get(source, 0) > 0:
6772
source_params = tech_params.get(source, {})
6873
capacity_kw = peak_demand_kw_yr1 * (energy_mix[source] / 100)
69-
annual_opex += (capacity_kw * source_params.get('capex_per_kw', 0)) * source_params.get('opex_rate', 0.015)
74+
opex_details_annual['o&m_cost'] += (capacity_kw * source_params.get('capex_per_kw', 0)) * source_params.get('opex_rate', 0.015)
75+
7076
if source == 'hydrogen_SOFC':
71-
energy_kwh = annual_demand_kwh * (energy_mix[source] / 100)
72-
fuel_cost = econ_assumptions['h2_fuel_cost'] * ((1 + econ_assumptions['fuel_escalation']) ** (simulation_year - 1))
73-
annual_opex += energy_kwh * fuel_cost
77+
opex_details_annual['h2_fuel_cost'] += (annual_demand_kwh * (energy_mix[source] / 100)) * (econ_assumptions['h2_fuel_cost'] * ((1 + econ_assumptions['fuel_escalation']) ** (simulation_year - 1)))
7478
elif source == 'NG_SOFC':
75-
energy_kwh = annual_demand_kwh * (energy_mix[source] / 100)
76-
fuel_cost = initial_ng_price * ((1 + econ_assumptions['fuel_escalation']) ** (simulation_year - 1))
77-
annual_opex += energy_kwh * fuel_cost
78-
total_emissions_kg += energy_kwh * source_params.get('carbon_emission_factor', 0)
79+
ng_kwh = annual_demand_kwh * (energy_mix[source] / 100)
80+
opex_details_annual['ng_fuel_cost'] += ng_kwh * (initial_ng_price * ((1 + econ_assumptions['fuel_escalation']) ** (simulation_year - 1)))
81+
total_emissions_kg += ng_kwh * source_params.get('carbon_emission_factor', 0)
82+
83+
opex_details_annual['carbon_tax_cost'] = 0
7984
if econ_assumptions['carbon_tax_year'] and simulation_year >= econ_assumptions['carbon_tax_year']:
80-
annual_opex += (total_emissions_kg / 1000) * econ_assumptions['carbon_tax_price']
85+
opex_details_annual['carbon_tax_cost'] = (total_emissions_kg / 1000) * econ_assumptions['carbon_tax_price']
86+
87+
annual_opex = sum(opex_details_annual.values())
8188

89+
# Accumulate Present Values
8290
total_opex_pv += annual_opex * discount_factor
8391
total_demand_pv_kwh += annual_demand_kwh * discount_factor
92+
for key, value in opex_details_annual.items():
93+
opex_breakdown_pv[key] = opex_breakdown_pv.get(key, 0) + (value * discount_factor)
8494

8595
results.append({'year': actual_year, 'annual_opex': annual_opex})
8696

8797
# --- 3. Final Summary Calculation ---
88-
total_capex_pv_for_tco = initial_capex + total_replacement_capex_pv
89-
tco_5yr = total_capex_pv_for_tco + total_opex_pv
98+
total_capex_pv = initial_capex + total_replacement_capex_pv
99+
tco_5yr = total_capex_pv + total_opex_pv
90100

91-
# For LCOE, we need to annualize the total investment over the asset lifetime
101+
# For LCOE, annualize the total investment over the asset lifetime
92102
if discount_rate > 0:
93103
crf = (discount_rate * (1 + discount_rate) ** asset_lifetime) / ((1 + discount_rate) ** asset_lifetime - 1)
94104
else:
95105
crf = 1 / asset_lifetime
96-
annualized_total_investment = total_capex_pv_for_tco * crf
97-
98-
# Average annual OPEX (PV)
99-
avg_annual_opex_pv = total_opex_pv / len(demand_profile)
106+
annualized_total_investment = total_capex_pv * crf
100107

101-
# Average annual demand (PV)
102-
avg_annual_demand_pv_kwh = total_demand_pv_kwh / len(demand_profile)
108+
avg_annual_opex_pv = total_opex_pv / config.get('simulation_period_years', 5)
109+
avg_annual_demand_pv_kwh = total_demand_pv_kwh / config.get('simulation_period_years', 5)
103110

104111
summary = {
105112
'5_Year_TCO': tco_5yr,
106113
'Total_Initial_CAPEX': initial_capex,
107-
'Total_CAPEX_PV': total_capex_pv_for_tco,
114+
'Total_CAPEX_PV': total_capex_pv,
108115
'Total_OPEX_PV': total_opex_pv,
109116
'LCOE_Avg_5yr': ((annualized_total_investment + avg_annual_opex_pv) / avg_annual_demand_pv_kwh) * 1000 if avg_annual_demand_pv_kwh > 0 else 0
110117
}
111118

112-
return pd.DataFrame(results), summary, capex_details, {}
119+
return pd.DataFrame(results), summary, capex_details, opex_breakdown_pv

0 commit comments

Comments
 (0)