Skip to content

Commit

Permalink
Test and notebook changes for fixed vs floating osw
Browse files Browse the repository at this point in the history
  • Loading branch information
brtietz committed Jun 18, 2024
1 parent 60f8075 commit 92bd051
Show file tree
Hide file tree
Showing 189 changed files with 3,601 additions and 1,027 deletions.
370 changes: 370 additions & 0 deletions debt_fraction_calculator/debt_fraction_dev.ipynb
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
}
Loading

0 comments on commit 92bd051

Please sign in to comment.