-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test and notebook changes for fixed vs floating osw
- Loading branch information
Showing
189 changed files
with
3,601 additions
and
1,027 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,370 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"attachments": {}, | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Development notebook for debt fraction calculator. Use this to test code changes without re-running the scrape.\n", | ||
"\n", | ||
"debt_fraction_calc.py has a few more comments and polish" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import pandas as pd\n", | ||
"import numpy as np\n", | ||
"import PySAM.Singleowner as singleowner\n", | ||
"import os\n", | ||
"import sys\n", | ||
"\n", | ||
"sys.path.insert(0, os.path.dirname(os.getcwd()))\n", | ||
"from lcoe_calculator.process_all import ProcessAll\n", | ||
"from lcoe_calculator.extractor import Extractor\n", | ||
"\n", | ||
"from lcoe_calculator.tech_processors import FixedOffShoreWindProc, FloatingOffShoreWindProc, LandBasedWindProc, DistributedWindProc,\\\n", | ||
" UtilityPvProc, CommPvProc, ResPvProc, UtilityPvPlusBatteryProc,\\\n", | ||
" CspProc, GeothermalProc, HydropowerProc, PumpedStorageHydroProc,\\\n", | ||
" NuclearProc, BiopowerProc\n", | ||
"\n", | ||
"from lcoe_calculator.macrs import MACRS_6, MACRS_16, MACRS_21" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# Data master version on sharepoint - empty string if you haven't renamed the file\n", | ||
"version_string = \"_v1.46\"\n", | ||
"\n", | ||
"# Path to data master spreadsheet\n", | ||
"data_master_filename = \"path/to/2024-ATB-Data_Workbook.xlsx\"\n", | ||
"\n", | ||
"techs = [UtilityPvPlusBatteryProc\n", | ||
" ]\n", | ||
"\n", | ||
"\n", | ||
"CRP_CHOICES = [20]\n", | ||
"scraper = ProcessAll(data_master_filename, techs=techs)\n", | ||
"scraper.process()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"df_itc, df_ptc = Extractor.get_tax_credits_sheet(data_master_filename)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"print(set(scraper.data.Parameter))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"fuel_filename = 'fuel_prices.csv'\n", | ||
"df_fuel = pd.read_csv(fuel_filename).set_index(\"Price\")\n", | ||
"df_fuel.columns = df_fuel.columns.astype(int)\n", | ||
"print(df_fuel)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"def calculate_debt_fraction(input_vals, debug=False):\n", | ||
" model = singleowner.default(\"GenericSystemSingleOwner\")\n", | ||
"\n", | ||
" analysis_period = 20\n", | ||
" ac_capacity = 1000 # kW\n", | ||
" capacity_factor = input_vals[\"CF\"]\n", | ||
" gen = [capacity_factor * ac_capacity] * 8760 # Distribute evenly throughout the year\n", | ||
"\n", | ||
" capex = input_vals[\"OCC\"]\n", | ||
" con_fin_costs = input_vals[\"CFC\"]\n", | ||
" initial_investment = capex * ac_capacity\n", | ||
" con_fin_total = con_fin_costs * ac_capacity\n", | ||
" o_and_m = input_vals[\"Fixed O&M\"]\n", | ||
" v_o_and_m = input_vals[\"Variable O&M\"]\n", | ||
" dscr = input_vals[\"DSCR\"]\n", | ||
"\n", | ||
" ## Set these here so we can adjust below\n", | ||
" irr_target = input_vals[\"IRR\"] \n", | ||
" tax_federal = input_vals[\"Tax Rate (Federal and State)\"] * 100\n", | ||
" tax_state = 0\n", | ||
" inflation = input_vals[\"Inflation Rate\"] * 100\n", | ||
"\n", | ||
" degradation = 0.0 # ATB presents average capactity factors\n", | ||
"\n", | ||
" model.value(\"analysis_period\", analysis_period)\n", | ||
" model.value(\"flip_target_year\", analysis_period)\n", | ||
" model.value(\"gen\", gen)\n", | ||
" model.value(\"system_pre_curtailment_kwac\", gen)\n", | ||
" model.value(\"system_capacity\", ac_capacity)\n", | ||
" model.value(\"cp_system_nameplate\", ac_capacity / 1000)\n", | ||
" model.value(\"total_installed_cost\", initial_investment)\n", | ||
"\n", | ||
" ## Single Owner should apply the O&M cost to each year, so no need to multiply by analysis period?\n", | ||
" model.value(\"om_capacity\", [o_and_m] ) \n", | ||
" model.value(\"om_production\", [v_o_and_m])\n", | ||
" if 'Fuel' in input_vals:\n", | ||
" model.value(\"om_fuel_cost\", [input_vals['Fuel']])\n", | ||
" if 'Heat Rate' in input_vals:\n", | ||
" model.value(\"system_heat_rate\", input_vals['Heat Rate'])\n", | ||
"\n", | ||
" model.value(\"degradation\", [degradation]) # Specify length 1 so degradation is applied each year. An array of 0.7 len(analysis_period) assumes degradation the first year, but not afterwards\n", | ||
" model.value(\"system_use_lifetime_output\", 0) # Do degradation in the financial model\n", | ||
"\n", | ||
" model.value(\"debt_option\", 1) # Use DSCR\n", | ||
" model.value(\"dscr\", dscr)\n", | ||
" # model.value(\"debt_percent\", 51.9)\n", | ||
" model.value(\"inflation_rate\", inflation)\n", | ||
" model.value(\"term_int_rate\", input_vals['Interest Rate Nominal'] * 100)\n", | ||
" model.value(\"term_tenor\", 18)\n", | ||
" model.value(\"real_discount_rate\", input_vals['Calculated Rate of Return on Equity Real'] * 100) ## \"real equity rate\" (also get this from data?)\n", | ||
" model.value(\"flip_target_percent\", irr_target) ## \"nominal equity rate\"\n", | ||
" model.value(\"ppa_escalation\", 0.0)\n", | ||
"\n", | ||
" model.value(\"federal_tax_rate\", [tax_federal])\n", | ||
" model.value(\"state_tax_rate\", [tax_state])\n", | ||
"\n", | ||
" # This group is included in fixed O&M\n", | ||
" model.value(\"insurance_rate\", 0)\n", | ||
" model.value(\"property_tax_rate\", 0)\n", | ||
" model.value(\"prop_tax_cost_assessed_percent\", 0)\n", | ||
"\n", | ||
" model.value(\"reserves_interest\", 0)\n", | ||
" model.value(\"salvage_percentage\", 0)\n", | ||
" model.value(\"months_receivables_reserve\", 0)\n", | ||
" model.value(\"months_working_reserve\", 0)\n", | ||
" model.value(\"dscr_reserve_months\", 0)\n", | ||
" model.value(\"equip1_reserve_cost\", 0)\n", | ||
" model.value(\"equip2_reserve_cost\", 0)\n", | ||
" model.value(\"equip3_reserve_cost\", 0)\n", | ||
" model.value(\"cost_debt_closing\", 0)\n", | ||
" model.value(\"cost_debt_fee\", 0)\n", | ||
" model.value(\"loan_moratorium\", 0)\n", | ||
" model.value(\"construction_financing_cost\", con_fin_total)\n", | ||
" model.value(\"itc_fed_percent\", [input_vals[\"ITC\"] * 100])\n", | ||
" model.value('itc_fed_percent_maxvalue', [1e38])\n", | ||
" model.value(\"itc_sta_amount\", [0])\n", | ||
" model.value(\"ptc_fed_amount\", [input_vals[\"PTC\"] / 1000]) # Convert $/MWh to $/kWh\n", | ||
"\n", | ||
" if input_vals[\"MACRS\"] == MACRS_6:\n", | ||
" model.value(\"depr_alloc_macrs_5_percent\", 100)\n", | ||
" model.value(\"depr_itc_fed_macrs_5\", 1)\n", | ||
" model.value(\"depr_itc_sta_macrs_5\", 1)\n", | ||
" model.value(\"depr_alloc_macrs_15_percent\", 0)\n", | ||
" model.value(\"depr_alloc_sl_20_percent\", 0)\n", | ||
" elif input_vals[\"MACRS\"] == MACRS_16:\n", | ||
" model.value(\"depr_alloc_macrs_5_percent\", 0)\n", | ||
" model.value(\"depr_alloc_macrs_15_percent\", 100)\n", | ||
" model.value(\"depr_itc_fed_macrs_15\", 1)\n", | ||
" model.value(\"depr_itc_sta_macrs_15\", 1)\n", | ||
" model.value(\"depr_alloc_sl_20_percent\", 0)\n", | ||
" elif input_vals[\"MACRS\"] == MACRS_21:\n", | ||
" model.value(\"depr_alloc_macrs_5_percent\", 0)\n", | ||
" model.value(\"depr_alloc_macrs_15_percent\", 0)\n", | ||
" model.value(\"depr_alloc_sl_20_percent\", 100)\n", | ||
" model.value(\"depr_itc_fed_sl_20\", 1)\n", | ||
" model.value(\"depr_itc_fed_sl_20\", 1)\n", | ||
" model.value(\"depr_alloc_custom_percent\", 0)\n", | ||
" model.value(\"depr_alloc_sl_5_percent\", 0)\n", | ||
" model.value(\"depr_alloc_sl_15_percent\", 0)\n", | ||
" model.value(\"depr_alloc_sl_39_percent\", 0)\n", | ||
" model.value(\"depr_bonus_fed\", 0)\n", | ||
" model.value(\"depr_bonus_sta\", 0)\n", | ||
" model.value(\"depr_bonus_fed_macrs_5\", 0)\n", | ||
" model.value(\"depr_bonus_sta_macrs_5\", 0)\n", | ||
" model.value(\"depr_bonus_fed_macrs_15\", 0)\n", | ||
" model.value(\"depr_bonus_sta_macrs_15\", 0)\n", | ||
"\n", | ||
" model.value(\"depr_fedbas_method\", 0)\n", | ||
" model.value(\"depr_stabas_method\", 0)\n", | ||
"\n", | ||
" model.value(\"ppa_soln_mode\", 0)\n", | ||
" model.value(\"payment_option\", 0)\n", | ||
"\n", | ||
" model.value('en_electricity_rates', 1 )\n", | ||
"\n", | ||
" model.execute()\n", | ||
"\n", | ||
" if debug:\n", | ||
" print(\"LCOE: \" + str(model.Outputs.lcoe_real)) #Cents / kWh - multiply by 10 to get $ / MWh\n", | ||
" print(\"NPV: \" + str(model.Outputs.project_return_aftertax_npv))\n", | ||
" print()\n", | ||
" print(\"IRR in target year: \" + str(model.Outputs.flip_target_irr))\n", | ||
" print(\"IRR at end of project: \" + str(model.Outputs.analysis_period_irr))\n", | ||
" print(\"O&M: \" + str(model.Outputs.cf_om_capacity_expense))\n", | ||
" print(\"PPA price: \" + str(model.Outputs.cf_ppa_price))\n", | ||
" print(\"Debt Principal: \" + str(model.Outputs.cf_debt_payment_principal))\n", | ||
" print(\"Debt Interest: \" + str(model.Outputs.cf_debt_payment_interest))\n", | ||
" print(\"Depreciation: \" + str(model.Outputs.cf_feddepr_total))\n", | ||
" print(\"Production: \" + str(model.Outputs.cf_energy_net))\n", | ||
" print(\"Tax \" + str(model.Outputs.cf_fedtax))\n", | ||
" print(\"ITC \" + str(model.Outputs.itc_total_fed))\n", | ||
" print(\"PTC \" + str(model.Outputs.cf_ptc_fed))\n", | ||
" print(\"Debt fraction \" + str(model.Outputs.debt_fraction))\n", | ||
"\n", | ||
" return model.Outputs.debt_fraction" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"d = scraper.data\n", | ||
"print(d.columns)\n", | ||
"print(set(d.Parameter))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"fin_cases = ['Market','R&D']\n", | ||
"\n", | ||
"d = scraper.data\n", | ||
"debt_frac_dict = {}\n", | ||
"\n", | ||
"years = range(2021, 2051)\n", | ||
"print (years)\n", | ||
"cols = [\"Technology\", \"Case\", *years]\n", | ||
"\n", | ||
"for tech in techs:\n", | ||
" for fin_case in fin_cases:\n", | ||
" print(\"Fin case \" , fin_case)\n", | ||
" debt_fracs = [tech.tech_name, fin_case]\n", | ||
" for year in years:\n", | ||
" input_vals = d[(d.DisplayName == tech.default_tech_detail) & (d.Case == fin_case) & (d.Scenario == 'Moderate') & (d.CRPYears == 20) & \n", | ||
" ((d.Parameter == 'Fixed O&M') | (d.Parameter == 'Variable O&M') |(d.Parameter == 'OCC') | (d.Parameter == 'CFC') | (d.Parameter == 'CF')\n", | ||
" | (d.Parameter == 'Heat Rate') | (d.Parameter == 'Fuel'))]\n", | ||
" input_vals = input_vals.set_index('Parameter')[year].to_dict()\n", | ||
"\n", | ||
" gen_vals = d[(d.Technology == tech.tech_name) & (d.CRPYears == 20) & (d.Case == fin_case) & \n", | ||
" ((d.Parameter == 'Inflation Rate') | (d.Parameter == 'Tax Rate (Federal and State)') | (d.Parameter == 'Calculated Rate of Return on Equity Real') | (d.Parameter == 'Interest Rate Nominal'))]\n", | ||
" gen_vals = gen_vals.set_index('Parameter')[year].to_dict()\n", | ||
"\n", | ||
" if tech.has_itc and tech.has_ptc and fin_case == 'Market':\n", | ||
" input_vals[\"PTC\"] = df_ptc.loc[tech.sheet_name][year]\n", | ||
" input_vals[\"ITC\"] = df_itc.loc[tech.sheet_name][year]\n", | ||
" else:\n", | ||
" input_vals[\"PTC\"] = 0\n", | ||
" input_vals[\"ITC\"] = 0\n", | ||
" input_vals[\"DSCR\"] = tech.dscr\n", | ||
" input_vals[\"IRR\"] = tech.irr_target\n", | ||
" if isinstance(tech.depreciation_schedule, list):\n", | ||
" input_vals[\"MACRS\"] = tech.depreciation_schedule\n", | ||
" elif isinstance(tech.depreciation_schedule, dict):\n", | ||
" input_vals[\"MACRS\"] = tech.depreciation_schedule[year]\n", | ||
" input_vals.update(gen_vals)\n", | ||
" debt_frac = calculate_debt_fraction(input_vals)\n", | ||
"\n", | ||
" debt_fracs.append(debt_frac / 100.0)\n", | ||
" \n", | ||
" debt_frac_dict[tech.tech_name + fin_case] = debt_fracs\n", | ||
"\n", | ||
"df_df = pd.DataFrame.from_dict(debt_frac_dict, orient='index', columns=cols)\n", | ||
"df_df.to_csv(\"2023_debt_fractions.csv\")\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"df_fuel.at['Natural Gas ($/MMBtu)', year]" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"\"\"\"\n", | ||
"if tech == NaturalGasProc:\n", | ||
" input_vals['Fuel'] = df_fuel.at['Natural Gas ($/MMBtu)', year]\n", | ||
"if tech == CoalProc:\n", | ||
" input_vals['Fuel'] = df_fuel.at['Coal ($/MMBtu)', year]\n", | ||
"\"\"\"" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"print(input_vals)\n", | ||
"\n", | ||
"print(debt_frac)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "atb_datamaster_etl", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.11.5" | ||
}, | ||
"orig_nbformat": 4, | ||
"vscode": { | ||
"interpreter": { | ||
"hash": "7453c7a7c4c6aacca0bd3e48c10e9f590f02fc03a145dba291554d026d9242d0" | ||
} | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
Oops, something went wrong.