8000 Lcoe branch by eccoope · Pull Request #1687 · pvlib/pvlib-python · GitHub
[go: up one dir, main page]

Skip to content

Lcoe branch #1687

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

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
49fd4e8
''
eccoope Mar 6, 2023
fb6ff2f
Merge branch 'main' of https://github.com/eccoope/pvlib-python-forked…
eccoope Mar 6, 2023
2204f18
''
eccoope Mar 6, 2023
af4b00b
resolved stickler issues
eccoope Mar 7, 2023
d7c606d
resolved stickler issues
eccoope Mar 7, 2023
9b86e11
resolved stickler issues
eccoope Mar 7, 2023
9f1e090
updated to be consistent suggested changes
eccoope Mar 7, 2023
a4fa101
''
eccoope Mar 7, 2023
fdea1b5
''
eccoope Mar 7, 2023
4c7cba8
''
eccoope Mar 7, 2023
7fdb96f
''
eccoope Mar 7, 2023
59df950
''
eccoope Mar 7, 2023
effdaa7
''
eccoope Mar 7, 2023
4284990
Resolve stickler failures
eccoope Mar 8, 2023
2bfba2e
Resolved stickler issues in simple_lcoe_calculator.py
eccoope Mar 8, 2023
e6f6938
Resolved stickler issues and linked references
eccoope Mar 8, 2023
b61a9cb
Resolved stickler failures
eccoope Mar 8, 2023
49f2631
Changed variable names + real/nominal clarification
eccoope Mar 8, 2023
388f9f4
Resolved stickler failure
eccoope Mar 8, 2023
a18f861
More stickler corrections
eccoope Mar 8, 2023
582c974
Encourage use of real discount rates
eccoope Mar 8, 2023
4161663
Encourage use of real discount rates
eccoope Mar 8, 2023
c0e31dc
Update pvlib/financial.py
eccoope Mar 9, 2023
912969d
Update pvlib/financial.py
eccoope Mar 9, 2023
a0a7cf1
Update pvlib/financial.py
eccoope Mar 9, 2023
17898a6
Update pvlib/financial.py
eccoope Mar 9, 2023
dce7e5f
Update pvlib/financial.py
eccoope Mar 9, 2023
1ea12b5
Update pvlib/financial.py
eccoope Mar 9, 2023
e124027
Update pvlib/financial.py
eccoope Mar 9, 2023
9d17c09
Apply suggestions from code review
eccoope Mar 9, 2023
83d6e02
Update financial.py
eccoope Mar 9, 2023
33c8238
Update test_financial.py
eccoope Mar 9, 2023
cd0ae02
Stickler for lcoe_sam_validation.py
eccoope Mar 10, 2023
92d7258
More stickler for lcoe_sam_validation.py
eccoope Mar 10, 2023
cae3d7b
more stickler for lcoe_sam_validation.py
eccoope Mar 10, 2023
7fc63e7
One last stickler thing
eccoope Mar 10, 2023
00df4f8
Remove "real" from wacc docstring
eccoope Mar 10, 2023
ab47596
Added a line to index.rst
eccoope Mar 15, 2023
7a039b7
Added last two authors to be consistent with version in main branch
eccoope Mar 16, 2023
ebec039
Merge branch 'main' into lcoe_branch
eccoope Mar 16, 2023
7136b84
Merge branch 'main' of https://github.com/eccoope/pvlib-python-forked…
eccoope Jun 21, 2023
41bde9c
Resolved conflicts in v0.9.5 and moved changes to v0.9.6
eccoope Jun 21, 2023
8aff9f0
Merge branch 'main' into lcoe_branch
eccoope Jun 21, 2023
925e155
Remove variable O&M caveatp
eccoope Jun 28, 2023
42b7823
Merge branch 'main' into lcoe_branch
eccoope Jun 28, 2023
0541e5b
Added system degradation rate to example
eccoope Jul 10, 2023
1441de6
Delete v0.9.6.rst
eccoope Jul 10, 2023
d2205c3
Merge branch 'pvlib:main' into lcoe_branch
eccoope Jul 10, 2023
77fb22c
Updated whatsnew v0.10.2.rst
eccoope Jul 10, 2023
b3c272e
Merge branch 'main' into lcoe_branch
eccoope Dec 13, 2023
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
Next Next commit
''
  • Loading branch information
eccoope committed Mar 6, 2023
commit 49fd4e8a47e9322ff0295fb166bfdab5ce1765ed
116 changes: 116 additions & 0 deletions pvlib/financial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import numpy as np

def lcoe(production=None, cap_cost=None, fixed_om=None):
"""
Levelized cost of electricity as described on pp.43 and 47-48 by [1]
Parameters
----------
production : np.array, or pd.Series, default None
Annual production [kWh/kW installed]
cap_cost : np.array, or pd.Series, default None
Initial and annual payments on capital costs [$/kW installed]
fixed_om : np.array, or pd.Series, default None
Annual payments on operations and maintenance costs [$/kW installed]

Returns
----------
LCOE [cents/kWh]

References
----------
.. [1] W. Short, D. J. Packey, and T. Holt, "A Manual for the Economic Evaluation of Energy Efficiency and Renewable Energy Technologies", NREL/TP-462-5173, 1995.
"""
if len(production)!=len(cap_cost) or len(cap_cost)!=len(fixed_om):
raise ValueError("Unequal input array lengths")
cost = cap_cost + fixed_om
return np.round(np.nansum(cost)*100/np.nansum(production),2)

def crf(rate, n_years):
"""
Capital recovery factor as described on pp. 23 by [1]
Parameters
----------
rate : float
Rate at which CRF is calculated
n_years: int
Number of years over which CRF is calculated

Returns
----------
crf : float
Capital recovery factor
References
----------
.. [1] W. Short, D. J. Packey, and T. Holt, "A Manual for the Economic Evaluation of Energy Efficiency and Renewable Energy Technologies", NREL/TP-462-5173, 1995.
"""
return np.round((rate*(1+rate)**n_years)/((1+rate)**n_years-1),8)

def nominal_to_real(nominal, rate):
"""
Inflation-adjusted rate described on pp. 6 by [1]
Parameters
----------
nominal : float
Nominal rate (does not include adjustments for inflation)
rate : float
Inflation rate

Returns
----------
Real rate (includes adjustments for inflation)

References
----------
.. [1] W. Short, D. J. Packey, and T. Holt, "A Manual for the Economic Evaluation of Energy Efficiency and Renewable Energy Technologies", NREL/TP-462-5173, 1995.
"""
return np.round((1+nominal)/(1+rate)-1, 8)

def real_to_nominal(real, rate):
"""
Rate without adjusting for inflation as described on pp. 6 by [1]
Parameters
----------
real : float
Real rate (includes adjustments for inflation)
rate : float
Inflation rate

Returns
----------
Nominal rate (does not include adjustments for inflation)

References
----------
.. [1] W. Short, D. J. Packey, and T. Holt, "A Manual for the Economic Evaluation of Energy Efficiency and Renewable Energy Technologies", NREL/TP-462-5173, 1995.
"""

return np.round((real+1)*(1+rate)-1, 8)

def wacc(loan_frac, rroi, rint, inflation_rate, tax_rate):
"""
Parameters
----------
loan_frac : float
Fraction of capital cost paid for with a loan
rroi : float
Real internal rate of return on investment
rint : float
Real interest rate
inflation_rate : float
Effective inflation rate
tax_rate : float
Tax rate

Returns
----------
wacc : float
Weighted average cost of capital

References
----------
.. [1] S. Blumsack, "Weighted Average Cost of Capital", The Pennsylvania State University, Available: http://www.e-education.psu.edu/eme801/node/585
"""
numerator = (1 + ((1 - loan_frac)*((1 + rroi)*(1 + inflation_rate)-1))
+ loan_frac*((1 + rint)*(1 + inflation_rate) - 1)*(1 - tax_rate))
denominator = 1 + inflation_rate
return np.round(numerator/denominator -1, 8)
77 changes: 77 additions & 0 deletions pvlib/tests/test_financial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import pandas as pd
import numpy as np
import sys
from pvlib import financial
from numpy.testing import assert_allclose

def test_lcoe_series():
n, cf = 20, 0.5
production = pd.Series(data=[cf*8670 for j in range(n)])
capex, loan_frac, my_crf, debt_tenor = 1000, 0.5, 0.05, n
cap_cost = pd.Series(data=[capex*loan_frac*my_crf for i in range(debt_tenor)] + [0 for j in range(debt_tenor, n)])
base_om = 25
fixed_om = pd.Series(data=[base_om for j in range(n)])

expected = 1.15
out = financial.lcoe(production=production, cap_cost=cap_cost, fixed_om=fixed_om)

assert_allclose(expected, out)

def test_lcoe_arrays():
n, cf = 20, 0.5
production = np.full(n, cf*8670)
capex, loan_frac, my_crf, debt_tenor = 1000, 0.5, 0.05, n
cap_cost = np.array([capex*loan_frac*my_crf for i in range(debt_tenor)] + [0 for j in range(debt_tenor, n)])
base_om = 25
fixed_om = np.full(n, base_om)
expected = 1.15

out = financial.lcoe(production=production, cap_cost=cap_cost, fixed_om=fixed_om)
assert_allclose(expected, out)

def test_lcoe_nans():
n, cf = 20, 0.5
production = np.full(n, cf*8670)
capex, loan_frac, my_crf, debt_tenor = 1000, 0.5, 0.05, n
cap_cost = np.array([capex*loan_frac*my_crf for i in range(debt_tenor)] + [0 for j in range(debt_tenor, n)])
base_om = 25.
fixed_om = np.full(n, base_om)
cap_cost[1] = np.nan
fixed_om[2] = np.nan
production[3] = np.nan
expected = 1.09

out = financial.lcoe(production=production, cap_cost=cap_cost, fixed_om=fixed_om)
assert_allclose(expected, out)

def test_crf():
rate, n = 0.05, 20
expected = 0.08024259

out = financial.crf(rate, n)
assert_allclose(expected, out)

def test_nominal_to_real():
nominal, rate = 0.04, 0.025
expected = 0.01463415

out = financial.nominal_to_real(nominal, rate)
assert_allclose(expected, out)

def test_real_to_nominal():
real, rate = 0.04, 0.025
expected = 0.066

out = financial.real_to_nominal(real, rate)
assert_allclose(expected, out)

def test_wacc():
loan_frac = 0.5
rroi = 0.12
rint = 0.04
inflation_rate = 0.025
tax_rate = 0.28
expected = 0.07098537

out = financial.wacc(loan_frac, rroi, rint, inflation_rate, tax_rate)
assert_allclose(expected, out)
0