# Copyright (c) 2018 Kelvin Say # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. library(FinCal) source('utility_functions.R') # --------------------------------------------------------------------------------------------------------------------------- # # --------------------------------------------------------------------------------------------------------------------------- process_Financial_Viability <- function(technical_summary, finance_info, tariff_info, costs_info, timing = FALSE, runIRR = FALSE) { if (timing) { start_time <- now() time_a <- start_time } inputs <- list('Finance' = finance_info, 'Tariff' = tariff_info, 'Costs' = costs_info, 'Technical' = technical_summary$Inputs) analysis_years <- finance_info$'Analysis Years' pv_count <- length(technical_summary$'PV Capacity (Wp)') battery_count <- length(technical_summary$'Battery Capacity (Wh)') # Costs: PV, Battery, System # -------------------------- v_pv_cost <- technical_summary$'PV Capacity (Wp)' / 1000 * costs_info$'PV Cost ($/kWp)' v_battery_cost <- technical_summary$'Battery Capacity (Wh)' / 1000 * costs_info$'Battery Cost ($/kWh)' temp_A <- matrix(v_pv_cost, nrow=pv_count, ncol=battery_count) temp_B <- matrix(v_battery_cost, nrow=pv_count, ncol=battery_count, byrow = TRUE) mat_system_cost <- temp_A + temp_B # Savings: PV, Battery, System # ---------------------------- v_mask <- rep(1, pv_count) for (i in 1:pv_count) { if (technical_summary$'PV Capacity (Wp)'[i] > tariff_info$'FiT System Limit (Wp)') { v_mask[i] <- 0 } } mat_pv_savings_import <- crossfill_2D_3D_matrix(technical_summary$Yearly$'Directly Used (kWh)', battery_count) mat_pv_savings_export <- crossfill_2D_3D_matrix(v_mask * (technical_summary$Yearly$'Generated (kWh)' - technical_summary$Yearly$'Directly Used (kWh)'), battery_count) mat_pv_savings <- round(mat_pv_savings_import * tariff_info$'Import ($/kWh)' + mat_pv_savings_export * tariff_info$'Export ($/kWh)', 2) mat_battery_savings_import <- technical_summary$Yearly$'Battery Discharged (kWh)' mat_battery_savings_export <- v_mask * (technical_summary$Yearly$'Exported (kWh)' - crossfill_2D_3D_matrix(technical_summary$Yearly$'Generated (kWh)' - technical_summary$Yearly$'Directly Used (kWh)', battery_count)) mat_battery_savings <- round(mat_battery_savings_import * tariff_info$'Import ($/kWh)' + mat_battery_savings_export * tariff_info$'Export ($/kWh)', 2) mat_system_savings_import <- mat_pv_savings_import + mat_battery_savings_import mat_system_savings_export <- mat_pv_savings_export + mat_battery_savings_export mat_system_savings <- round(mat_system_savings_import * tariff_info$'Import ($/kWh)' + mat_system_savings_export * tariff_info$'Export ($/kWh)', 2) if (timing) { print(paste("--> Savings calculated:", round(now() - time_a,2), "seconds")) time_a <- now() } # Cash flow calculation (analysis_years): PV, Battery, System # ----------------------------------------------------------- mat_pv_cf <- array(0, dim=c(pv_count, battery_count, analysis_years+1)) for (i in 1:pv_count) { capital_cost <- v_pv_cost[i] for (j in 1:battery_count) { savings_import <- mat_pv_savings_import[i,j,] savings_export <- mat_pv_savings_export[i,j,] v_savings_yrs <- savings_import * tariff_info$'Import ($/kWh)' * (1 + tariff_info$'Import Inflation (%)') ^ c(0:(analysis_years-1)) + savings_export * tariff_info$'Export ($/kWh)' * (1 + tariff_info$'Export Inflation (%)') ^ c(0:(analysis_years-1)) mat_pv_cf[i,j,] <- c(-capital_cost, v_savings_yrs) } } mat_battery_cf <- array(0, dim=c(pv_count, battery_count, analysis_years+1)) for (j in 1:battery_count) { capital_cost <- v_battery_cost[j] for (i in 1:pv_count) { savings_import <- mat_battery_savings_import[i,j,] savings_export <- mat_battery_savings_export[i,j,] v_savings_yrs <- savings_import * tariff_info$'Import ($/kWh)' * (1 + tariff_info$'Import Inflation (%)') ^ c(0:(analysis_years-1)) + savings_export * tariff_info$'Export ($/kWh)' * (1 + tariff_info$'Export Inflation (%)') ^ c(0:(analysis_years-1)) mat_battery_cf[i,j,] <- c(-capital_cost, v_savings_yrs) } } mat_system_cf <- array(0, dim=c(pv_count, battery_count, analysis_years+1)) for (i in 1:pv_count) { for (j in 1:battery_count) { capital_cost <- mat_system_cost[i,j] savings_import <- mat_system_savings_import[i,j,] savings_export <- mat_system_savings_export[i,j,] v_savings_yrs <- savings_import * tariff_info$'Import ($/kWh)' * (1 + tariff_info$'Import Inflation (%)') ^ c(0:(analysis_years-1)) + savings_export * tariff_info$'Export ($/kWh)' * (1 + tariff_info$'Export Inflation (%)') ^ c(0:(analysis_years-1)) mat_system_cf[i,j,] <- c(-capital_cost, v_savings_yrs) } } if (timing) { print(paste("--> Cash flow calculated:", round(now() - time_a,2), "seconds")) time_a <- now() } # Payback (discounted) calculation: PV, Battery, System # ------------------------------------------------------ mat_pv_pbt <- matrix(0, nrow=pv_count, ncol=battery_count) mat_battery_pbt <- matrix(0, nrow=pv_count, ncol=battery_count) mat_system_pbt <- matrix(0, nrow=pv_count, ncol=battery_count) for (i in 1:pv_count) { for (j in 1:battery_count) { mat_pv_pbt[i,j] <- dpb(finance_info$'Discount Rate (%)', mat_pv_cf[i,j,]) mat_battery_pbt[i,j] <- dpb(finance_info$'Discount Rate (%)', mat_battery_cf[i,j,]) mat_system_pbt[i,j] <- dpb(finance_info$'Discount Rate (%)', mat_system_cf[i,j,]) } } if (timing) { print(paste("--> Discounted Payback calculated:", round(now() - time_a,2), "seconds")) time_a <- now() } # NPV calculation: PV, Battery, System # ------------------------------------ mat_pv_npv <- matrix(0, nrow=pv_count, ncol=battery_count) mat_battery_npv <- matrix(0, nrow=pv_count, ncol=battery_count) mat_system_npv <- matrix(0, nrow=pv_count, ncol=battery_count) for (i in 1:pv_count) { for (j in 1:battery_count) { mat_pv_npv[i,j] <- npv(finance_info$'Discount Rate (%)', mat_pv_cf[i,j,]) mat_battery_npv[i,j] <- npv(finance_info$'Discount Rate (%)', mat_battery_cf[i,j,]) mat_system_npv[i,j] <- npv(finance_info$'Discount Rate (%)', mat_system_cf[i,j,]) } } if (timing) { print(paste("--> NPV calculated:", round(now() - time_a,2), "seconds")) time_a <- now() } # Profit Index calculation: PV, Battery, System # --------------------------------------------- mat_pv_PI <- 1 + (mat_pv_npv / matrix(v_pv_cost, nrow=pv_count, ncol=battery_count)) mat_battery_PI <- 1 + (mat_battery_npv / matrix(v_battery_cost, nrow=pv_count, ncol=battery_count, byrow=TRUE)) mat_system_PI <- 1 + (mat_system_npv / mat_system_cost) # Internal Rate of Return calculation: PV, Battery, System # -------------------------------------------------------- mat_pv_irr <- matrix(NaN, nrow=pv_count, ncol=battery_count) mat_battery_irr <- matrix(NaN, nrow=pv_count, ncol=battery_count) mat_system_irr <- matrix(NaN, nrow=pv_count, ncol=battery_count) if (runIRR) { for (i in 1:pv_count) { for (j in 1:battery_count) { if (mat_pv_npv[i,j] > 0) { mat_pv_irr[i,j] <- tryCatch(irr(mat_pv_cf[i,j,]), error=function(e) {NaN}) } if (mat_battery_npv[i,j] > 0) { mat_battery_irr[i,j] <- tryCatch(irr(mat_battery_cf[i,j,]), error=function(e) {NaN}) } if (mat_system_npv[i,j] > 0) { mat_system_irr[i,j] <- tryCatch(irr(mat_system_cf[i,j,]), error=function(e) {NaN}) } } } } if (timing) { print(paste("--> IRR calculated:", round(now() - time_a,2), "seconds")) time_a <- now() print(paste("====> COMPLETED <=====")) print(round(now() - start_time)) } # Combine results for global output return(list(Inputs = inputs, PV.Costs = v_pv_cost, Battery.Costs = v_battery_cost, System.Costs = mat_system_cost, PV.Savings = round(mat_pv_savings, 2), Battery.Savings = round(mat_battery_savings, 2), System.Savings = round(mat_system_savings, 2), PV.Payback = mat_pv_pbt, Battery.Payback = mat_battery_pbt, System.Payback = mat_system_pbt, PV.CashFlow = mat_pv_cf, Battery.CashFlow = mat_battery_cf, System.CashFlow = mat_system_cf, PV.NPV = round(mat_pv_npv, 2), Battery.NPV = round(mat_battery_npv, 2), System.NPV = round(mat_system_npv, 2), PV.PI = mat_pv_PI, Battery.PI = mat_battery_PI, System.PI = mat_system_PI, PV.IRR = round(mat_pv_irr, 4), Battery.IRR = round(mat_battery_irr, 4), System.IRR = round(mat_system_irr, 4))) }