From c9083688ee449d506ba610fde8783522d3c65ce2 Mon Sep 17 00:00:00 2001 From: Zahra Keshavarz Moraveji Date: Tue, 3 Dec 2024 12:01:09 -0500 Subject: [PATCH] Upload files to "/" Function to calculate PV LCOE --- CMM-PV-20242511.py | 209 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 CMM-PV-20242511.py diff --git a/CMM-PV-20242511.py b/CMM-PV-20242511.py new file mode 100644 index 0000000..fcfa8d5 --- /dev/null +++ b/CMM-PV-20242511.py @@ -0,0 +1,209 @@ +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