PV_Economic_Metrics/main-codes/CMM-PV-20242511.py
Zahra-K-Moraveji 725d6d1e48 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	main-codes/CMM-PV-20242511.py
2024-12-03 12:28:43 -05:00

210 lines
8.4 KiB
Python

import pandas as pd
import numpy as np
import hub.helpers.constants as cte
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.results_factory import ResultFactory
inflation_rate = 0.03
discount_rate = 0.05
period = 25
installation_cost = 0
tax_deduct= 0
incentive= 0
capacity =30
degradation_rate = 0.01
year_of_replacement_list= [12]
replacement_ratio = 0.1
maintenance_cost_ratio =0.01
dataframe_path= r'C:\Users\z_keshav\CMM_PV\data\test.csv'
Building_function = "residential"
def calculate_pv_system_metrics(
dataframe_path, # input from Hub
Building_function, # input from Hub
inflation_rate,
discount_rate,
period,
capacity, # input from Hub
degradation_rate,
year_of_replacement_list,
replacement_ratio,
maintenance_cost_ratio,
installation_cost=0,
tax_deduct=0,
incentive=0,
):
# Read the data
dataframe = pd.read_csv(dataframe_path)
building_hourly_consumption = dataframe['GRID_kWh'] # input from Hub
PV_hourly_generation = dataframe['PV_roofs_top_E_kWh'] # input from Hub
# Defining tariff based on building function
if Building_function == "residential": # Rate D when the maximum power demand has reached 50 kW or more
grid_current_tariff = 0.06704 # Residential tariff in $/kWh
elif Building_function == "commercial": # Rate G: General rate for small-power customers with demand ≤ 50 kW
grid_current_tariff = 0.11518 # Commercial tariff in $/kWh
# Initial Calculations for Year 1
first_year_generation_PV = PV_hourly_generation.sum()
first_year_self_consumption = np.minimum(PV_hourly_generation, building_hourly_consumption).sum()
first_year_grid_purchase = np.maximum(building_hourly_consumption - PV_hourly_generation, 0).sum()
first_year_PV_export = np.maximum(PV_hourly_generation - building_hourly_consumption, 0).sum()
# Cost per kW determination
if capacity <= 2.5:
cost_per_kW = 4000
elif 2.5 < capacity <= 5:
cost_per_kW = 3000
elif 5 < capacity <= 10:
cost_per_kW = 2500
elif 10 < capacity <= 15:
cost_per_kW = 2300
elif 15 < capacity <= 20:
cost_per_kW = 2000
elif 20 < capacity <= 10000:
cost_per_kW = 1800
else:
cost_per_kW = 1449
# Initial costs
initial_cost = capacity * cost_per_kW
# Discounted metrics initialization
discounted_generation_per_year = {}
discounted_self_consumption_per_year = {}
discounted_building_export_per_year = {}
discounted_grid_purchase_per_year = {}
discounted_total_generation = 0
discounted_total_self_consumption = 0
discounted_total_building_export = 0
discounted_total_grid_purchase = 0
discounted_annual_cost = {}
discounted_total_cost = 0
discounted_income_per_year = {}
total_discounted_income = 0
total_discounted_net_metering_income = 0
# Replacement costs calculation
replacement_cost = {
year: capacity * cost_per_kW * replacement_ratio * ((1 + inflation_rate) ** year) / (
(1 + discount_rate) ** year)
for year in year_of_replacement_list
}
# Yearly calculations
for year in range(1, period + 1):
# Apply degradation to PV generation for the current year
PV_hourly_generation_degraded = PV_hourly_generation * ((1 - degradation_rate) ** (year - 1))
# Hourly self-consumption and export considering degraded generation
building_hourly_self_consumption = np.minimum(PV_hourly_generation_degraded, building_hourly_consumption)
building_hourly_export = np.maximum(PV_hourly_generation_degraded - building_hourly_consumption, 0)
building_hourly_grid_purchase = np.maximum(building_hourly_consumption - PV_hourly_generation_degraded, 0).sum()
# Annual values
annual_self_consumption = building_hourly_self_consumption.sum()
annual_generation = PV_hourly_generation_degraded.sum()
annual_PV_export = building_hourly_export.sum()
annual_grid_purchase = building_hourly_grid_purchase.sum()
# Discounted values
discounted_generation = annual_generation / ((1 + discount_rate) ** year)
discounted_self_consumption = annual_self_consumption / ((1 + discount_rate) ** year)
discounted_building_export = annual_PV_export / ((1 + discount_rate) ** year)
discounted_grid_purchase = annual_grid_purchase / ((1 + discount_rate) ** year)
# Add to total discounted values
discounted_generation_per_year[year] = discounted_generation
discounted_self_consumption_per_year[year] = discounted_self_consumption
discounted_building_export_per_year[year] = discounted_building_export
discounted_grid_purchase_per_year[year] = discounted_grid_purchase
# Calculate total values in Life Cycle
discounted_total_generation += discounted_generation
discounted_total_self_consumption += discounted_self_consumption
discounted_total_building_export += discounted_building_export
discounted_total_grid_purchase += discounted_grid_purchase
# Annual costs
annual_opex = initial_cost * maintenance_cost_ratio * ((1 + inflation_rate) ** year) / (
(1 + discount_rate) ** year)
annual_cost = (
initial_cost if year == 1
else annual_opex + replacement_cost.get(year, 0)
)
discounted_annual_cost[year] = annual_cost
discounted_total_cost += annual_cost
# Tariff adjustment for income
inflated_grid_tariff = grid_current_tariff * ((1 + inflation_rate) ** (year - 1))
discounted_factor = ((1 + discount_rate) ** year) ** -1
# Income from self-consumption and net metering
self_consumption_income = discounted_self_consumption * inflated_grid_tariff
net_metering_income = min(annual_PV_export, first_year_grid_purchase) * inflated_grid_tariff * discounted_factor
tax_deduction_income = (
initial_cost * (1 + tax_deduct) * ((1 - tax_deduct) ** (year - 1)) * tax_deduct
)
annual_income = self_consumption_income + net_metering_income + tax_deduction_income
discounted_income_per_year[year] = annual_income
total_discounted_income += annual_income
total_discounted_net_metering_income += net_metering_income
total_discounted_income += incentive
# LCOE calculations
if discounted_total_generation == 0:
raise ValueError("Discounted generation is zero, cannot calculate LCOE.")
# To compute the LCOE for exported energy accurately,
# you should isolate the portion of the discounted income that comes only from energy exported to the grid,
# over the total discounted exported energy
# Loec of purchasing from grid is same as tariff
lcoe_pv = discounted_total_cost / discounted_total_generation
total_transaction = (
discounted_total_self_consumption +
discounted_total_building_export +
discounted_total_grid_purchase
)
# lcoe of exported electricity for net metering
lcoe_export = (
total_discounted_net_metering_income / discounted_total_building_export if discounted_total_building_export > 0 else 0)
# lcoe of the whole system combining various transactions
lcoe_system = (
(discounted_total_self_consumption / total_transaction) * lcoe_pv +
(discounted_total_grid_purchase / total_transaction) * grid_current_tariff -
(discounted_total_building_export / total_transaction) * lcoe_export
)
# NPV calculation
npv = total_discounted_income - discounted_total_cost
return {
'LCOE_PV': lcoe_pv,
'LCOE_system': lcoe_system,
'NPV': npv,
'Annual_PV_generation': first_year_generation_PV,
'Annual_building_self_consumption': first_year_self_consumption,
'Annual_grid_purchase': first_year_grid_purchase,
'Annual_PV_export': first_year_PV_export,
'Discounted_total_cost': discounted_total_cost,
'Total_discounted_income': total_discounted_income,
'Discounted_generation_per_year': discounted_generation_per_year,
'Discounted_self_consumption_per_year': discounted_self_consumption_per_year,
'Discounted_annual_cost': discounted_annual_cost,
'Discounted_income_per_year': discounted_income_per_year
}
#example