Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split osw sheets #18

Merged
merged 3 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading