- 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.1k
 
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
          
     Closed
      
      
    
  
     Closed
                    Lcoe branch #1687
Changes from all commits
      Commits
    
    
            Show all changes
          
          
            50 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      49fd4e8
              
                ''
              
              
                eccoope fb6ff2f
              
                Merge branch 'main' of https://github.com/eccoope/pvlib-python-forked…
              
              
                eccoope 2204f18
              
                ''
              
              
                eccoope af4b00b
              
                resolved stickler issues
              
              
                eccoope d7c606d
              
                resolved stickler issues
              
              
                eccoope 9b86e11
              
                resolved stickler issues
              
              
                eccoope 9f1e090
              
                updated to be consistent suggested changes
              
              
                eccoope a4fa101
              
                ''
              
              
                eccoope fdea1b5
              
                ''
              
              
                eccoope 4c7cba8
              
                ''
              
              
                eccoope 7fdb96f
              
                ''
              
              
                eccoope 59df950
              
                ''
              
              
                eccoope effdaa7
              
                ''
              
              
                eccoope 4284990
              
                Resolve stickler failures
              
              
                eccoope 2bfba2e
              
                Resolved stickler issues in simple_lcoe_calculator.py
              
              
                eccoope e6f6938
              
                Resolved stickler issues and linked references
              
              
                eccoope b61a9cb
              
                Resolved stickler failures
              
              
                eccoope 49f2631
              
                Changed variable names + real/nominal clarification
              
              
                eccoope 388f9f4
              
                Resolved stickler failure
              
              
                eccoope a18f861
              
                More stickler corrections
              
              
                eccoope 582c974
              
                Encourage use of real discount rates
              
              
                eccoope 4161663
              
                Encourage use of real discount rates
              
              
                eccoope c0e31dc
              
                Update pvlib/financial.py
              
              
                eccoope 912969d
              
                Update pvlib/financial.py
              
              
                eccoope a0a7cf1
              
                Update pvlib/financial.py
              
              
                eccoope 17898a6
              
                Update pvlib/financial.py
              
              
                eccoope dce7e5f
              
                Update pvlib/financial.py
              
              
                eccoope 1ea12b5
              
                Update pvlib/financial.py
              
              
                eccoope e124027
              
                Update pvlib/financial.py
              
              
                eccoope 9d17c09
              
                Apply suggestions from code review
              
              
                eccoope 83d6e02
              
                Update financial.py
              
              
                eccoope 33c8238
              
                Update test_financial.py
              
              
                eccoope cd0ae02
              
                Stickler for lcoe_sam_validation.py
              
              
                eccoope 92d7258
              
                More stickler for lcoe_sam_validation.py
              
              
                eccoope cae3d7b
              
                more stickler for lcoe_sam_validation.py
              
              
                eccoope 7fc63e7
              
                One last stickler thing
              
              
                eccoope 00df4f8
              
                Remove "real" from wacc docstring
              
              
                eccoope ab47596
              
                Added a line to index.rst
              
              
                eccoope 7a039b7
              
                Added last two authors to be consistent with version in main branch
              
              
                eccoope ebec039
              
                Merge branch 'main' into lcoe_branch
              
              
                eccoope 7136b84
              
                Merge branch 'main' of https://github.com/eccoope/pvlib-python-forked…
              
              
                eccoope 41bde9c
              
                Resolved conflicts in v0.9.5 and moved changes to v0.9.6
              
              
                eccoope 8aff9f0
              
                Merge branch 'main' into lcoe_branch
              
              
                eccoope 925e155
              
                Remove variable O&M caveatp
              
              
                eccoope 42b7823
              
                Merge branch 'main' into lcoe_branch
              
              
                eccoope 0541e5b
              
                Added system degradation rate to example
              
              
                eccoope 1441de6
              
                Delete v0.9.6.rst
              
              
                eccoope d2205c3
              
                Merge branch 'pvlib:main' into lcoe_branch
              
              
                eccoope 77fb22c
              
                Updated whatsnew v0.10.2.rst
              
              
                eccoope b3c272e
              
                Merge branch 'main' into lcoe_branch
              
              
                eccoope File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or 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,193 @@ | ||
| """ | ||
| LCOE Calculation | ||
| ================ | ||
| 
     | 
||
| Example of an LCOE calculation for a utility-scale site in Albuquerque, NM | ||
| using the approach implemented by NREL's SAM software | ||
| """ | ||
| 
     | 
||
| # This example shows usage of pvlib's lcoe calculation with | ||
| # :py:meth:`pvlib.financial.lcoe`, :py:meth:`pvlib.financial.wacc`, | ||
| # :py:meth:`pvlib.financial.nominal_to_real`, and | ||
| # :py:meth:`pvlib.financial.crf` to generate a Series of annual cost and | ||
| # production data, and a real LCOE. TMY GHI, DNI, and DHI irradiance data | ||
| # for Albuquerque is loaded from the NSRDB and | ||
| # :py:meth:`pvlib.location.get_solarposition` is used with | ||
| # :py:meth:`pvlib.irradiance.get_total_irradiance`to calculate POA | ||
| # irradiance. DC energy production is calculated with | ||
| # :py:meth:`pvlib.pvsystem.pvwatts_dc` to get annual AC power output. | ||
| # Capital cost is calculated using the FCR method described here: | ||
| # http://samrepo.nrelcloud.org/help/index.html?fin_lcoefcr.htm with real | ||
| # discount rates. Construction interest is assumed to be zero. Input values | ||
| # with an asterisk were sourced from NREL's ATB projections for a residential | ||
| # system in 2022 with moderate | ||
| # technological advancement or the set of financial assumptions under which | ||
| # NREL produces the ATB. Monthly POA output [kWh/m^2], annual AC output [kWh], | ||
| # and LCOE should match values calculated by SAM. | ||
| 
     | 
||
| import numpy as np | ||
| import pandas as pd | ||
| import datetime | ||
| from pvlib import location | ||
| from pvlib import irradiance | ||
| from pvlib import temperature | ||
| from pvlib import pvsystem | ||
| from pvlib import inverter | ||
| from pvlib import financial | ||
| # from .conftest import DATA_DIR | ||
| 
     | 
||
| from pvlib.tests.conftest import DATA_DIR | ||
| 
     | 
||
| # Get annual AC output | ||
| 
     | 
||
| # Installed DC capacity [W] (total is 1 MW) | ||
| installed_dc = 1000000 | ||
| 
     | 
||
| # Surface tilt and azimuth | ||
| tilt, surface_azimuth = 30, 180 | ||
| 
     | 
||
| # Set Albuquerque as location | ||
| lat, lon, elev = 35.054942, -106.540485, 1657.8 | ||
| loc = location.Location(lat, lon, altitude=elev) | ||
| 
     | 
||
| # Albuquerque TMY data from NSRDB | ||
| data_file = DATA_DIR / 'albuquerque_tmy.csv' | ||
| data = pd.read_csv(data_file, skiprows=[0, 1]) | ||
| 
     | 
||
| # Set DatetimeIndex for data | ||
| data.set_index(pd.DatetimeIndex(data[['Month', 'Day', 'Hour', 'Minute']] | ||
| .apply(lambda x: | ||
| datetime.datetime(2022, x['Month'], | ||
| x['Day'], | ||
| x['Hour'], | ||
| x['Minute']), | ||
| axis=1)), inplace=True) | ||
| 
     | 
||
| # loc.get_solarposition() assumes UTC unless times is localized | ||
| # but Albuquerque is in Etc/GMT-7 | ||
| temp = loc.get_solarposition(times=pd.date_range(start=data.index[0] | ||
| + pd.Timedelta(7, 'h'), | ||
| end=data.index[-1] | ||
| + pd.Timedelta(7, 'h'), | ||
| freq='1H')) | ||
| # Shift index back to align with Etc/GMT-7 | ||
| solar_position = temp.set_index(temp.index.shift(periods=-7, freq='1H')) | ||
| 
     | 
||
| # Get POA and apply AOI modifier to direct and diffuse components | ||
| poa_irrad = irradiance.get_total_irradiance( | ||
| surface_tilt=tilt, surface_azimuth=surface_azimuth, | ||
| dni=data['DNI'], ghi=data['GHI'], dhi=data['DHI'], | ||
| solar_zenith=solar_position['zenith'], | ||
| solar_azimuth=solar_position['azimuth'], | ||
| albedo=data['Surface Albedo'])['poa_global'] | ||
| 
     | 
||
| # Calulate and display daily/monthly stats | ||
| daily_ghi = data['GHI'].groupby(data.index.map(lambda x: x.date())).sum().\ | ||
| mean()/1000 | ||
| daily_dhi = data['DHI'].groupby(data.index.map(lambda x: x.date())).sum().\ | ||
| mean()/1000 | ||
| daily_dni = data['DNI'].groupby(data.index.map(lambda x: x.date())).sum().\ | ||
| mean()/1000 | ||
| monthly_poa = poa_irrad.groupby(poa_irrad.index.map(lambda x: | ||
| x.date().month)).\ | ||
| sum()/1000 | ||
| 
     | 
||
| print('Daily average GHI is ' + str(np.round(daily_ghi, 3)) + ' kWh/m^2') | ||
| print('Daily average DHI is ' + str(np.round(daily_dhi, 3)) + ' kWh/m^2') | ||
| print('Daily average DNI is ' + str(np.round(daily_dni, 2)) + ' kWh/m^2') | ||
| print('Monthly POA averages [kWh/m^2]:') | ||
| print(monthly_poa) | ||
| 
     | 
||
| # Get system losses | ||
| losses = pvsystem.pvwatts_losses()/100 | ||
| 
     | 
||
| # Get cell temperature | ||
| cell_temp = temperature.pvsyst_cell(poa_irrad, data['Temperature'], | ||
| data['Wind Speed']) | ||
| 
     | 
||
| # Get hourly DC output using PVWatts [W DC] | ||
| dc_power = pvsystem.pvwatts_dc(poa_irrad, cell_temp, installed_dc, | ||
| -0.0037) * (1 - losses) | ||
| 
     | 
||
| # Get hourly AC output using PVWatts [W AC] | ||
| ac_power = inverter.pvwatts(dc_power, installed_dc/1.1) | ||
| 
     | 
||
| # Check that AC power data is evenly spaced over hour increments | ||
| if ~np.all(np.unique(np.diff(ac_power.index)/np.timedelta64(1, 'h')) == 1): | ||
| raise ValueError | ||
| 
     | 
||
| # Riemann-sum to get annual AC output [kWh] | ||
| annual_ac_output = ac_power.sum()/1000 | ||
| print('Annual AC output is ' + str(np.round(annual_ac_output, 2)) + ' kWh') | ||
| 
     | 
||
| # Period of financial analysis | ||
| n = 20 | ||
| 
     | 
||
| # Assume system degradation rate is 1% | ||
| sdr = 0.01 | ||
| 
     | 
||
| # Apply degradation rate to AC production over analysis period | ||
| production = np.array([annual_ac_output*(1 - sdr)**i for i in range(n)]) | ||
| 
     | 
||
| # Total installed capital costs [$] * | ||
| capex = 1119.82*installed_dc/1000 | ||
| 
     | 
||
| # Fixed O&M costs [$] * | ||
| fixed_op_cost = np.full(n, 19.95*installed_dc/1000) | ||
| 
     | 
||
| # Inflation rate * | ||
| inflation_r = 0.025 | ||
| 
     | 
||
| # Nominal interest rate * | ||
| interest_r = 0.04 | ||
| 
     | 
||
| # Real interest rate | ||
| rint = financial.nominal_to_real(interest_r, inflation_r) | ||
| 
     | 
||
| # Nominal internal rate of return * | ||
| irr = 0.0775 | ||
| 
     | 
||
| # Real internal rate of return | ||
| rroe = financial.nominal_to_real(irr, inflation_r) | ||
| 
     | 
||
| # Fraction of capital cost covered by a loan * | ||
| loan_frac = 0.518577595078774 | ||
| 
     | 
||
| # Effective tax rate * | ||
| tax_r = 0.2574 | ||
| 
     | 
||
| # Real weighted average cost of capital | ||
| my_wacc = financial.wacc(loan_frac, rroe, rint, inflation_r, tax_r) | ||
| print('Real weighted average cost of capital is ' + str(np.round(my_wacc, 5))) | ||
| 
     | 
||
| # Depreciation schedule | ||
| dep_sch = pd.Series([20, 32, 19.2, 11.52, 11.52, 5.76])/100 | ||
| 
     | 
||
| # Present value of depreciation | ||
| pvdep = np.sum([dep_sch.at[j]/((1 + my_wacc)*(1 + inflation_r))**(j+1) | ||
| for j in range(len(dep_sch))]) | ||
| 
     | 
||
| # Project financing factor | ||
| pff = (1 - (tax_r*pvdep))/(1 - tax_r) | ||
| 
     | 
||
| # Construction financing factor | ||
| cff = 1 | ||
| 
     | 
||
| # Capital recovery factor | ||
| my_crf = financial.crf(my_wacc, n) | ||
| 
     | 
||
| # Fixed charge rate | ||
| fcr = my_crf*pff*cff | ||
| print('Fixed charge rate is ' + str(np.round(fcr, 5))) | ||
| 
     | 
||
| debt_tenor = n | ||
| 
     | 
||
| # Annuity (annual payment) on total capital cost [$] | ||
| cap_cost = np.full(n, capex*fcr) | ||
| print('Annual payment on capital cost is $' + str(np.round(cap_cost[0], 2))) | ||
| 
     | 
||
| # Call lcoe() | ||
| my_lcoe = financial.lcoe(production=production, cap_cost=cap_cost, | ||
| fixed_om=fixed_op_cost) | ||
| 
     | 
||
| print('Real LCOE = ' + str(my_lcoe) + str(' cents/kWh')) | 
  
    
      This file contains hidden or 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,65 @@ | ||
| """ | ||
| LCOE Calculation | ||
| ================ | ||
| 
     | 
||
| Example of an LCOE calculation using an approach implemented in NREL's "Simple | ||
| LCOE Calculator", accessible at http://www.nrel.gov/analysis/tech-lcoe.html | ||
| """ | ||
| # %% | ||
| # This example shows basic usage of pvlib's lcoe calculation with | ||
| # :py:meth:`pvlib.financial.lcoe` and :py:meth:`pvlib.financial.crf`. | ||
| # The example shown here will generate a Series of annual cost and production | ||
| # data, and a numerical LCOE. To be comparable with NREL's implemenation, | ||
| # this example adheres to the following assumptions: that energy production | ||
| # and O&M costs are constant and that the entire project is financed with a | ||
| # loan. Input values for CAPEX, capacity factor, and O&M were sourced from | ||
| # NREL's ATB for a residential system in 2022 located in Resource Class 5 | ||
| # with moderate technological advancement. The discount rate is set to the | ||
| # value recommended in NREL's implementation. | ||
| 
     | 
||
| import numpy as np | ||
| import pandas as pd | ||
| from pvlib import financial | ||
| 
     | 
||
| # Analysis period | ||
| n = 20 | ||
| 
     | 
||
| # Capacity factor | ||
| cf = 0.15357857 | ||
| 
     | 
||
| # Constant annual energy production | ||
| energy = np.full(n, cf*8760) | ||
| 
     | 
||
| # Real discount rate | ||
| discount_rate = 0.03 | ||
| 
     | 
||
| # Capital recovery factor | ||
| my_crf = financial.crf(discount_rate, n) | ||
| 
     | 
||
| # CAPEX | ||
| capex = 2443.45 | ||
| 
     | 
||
| # Fraction of capital cost | ||
| loan_frac = 1 | ||
| 
     | 
||
| # Annual capital costs | ||
| cap_cost = np.array([capex*loan_frac*my_crf for i in range(n)]) | ||
| 
     | 
||
| # Constant annual O&M | ||
| fixed_om = pd.Series(data=[26.98 for j in range(n)]) | ||
| 
     | 
||
| # Put data in table and display | ||
| table = pd.DataFrame(columns=['Production [kWh/kW]', 'Capital cost [$/kW]', | ||
| 'O&M [$/kW]']) | ||
| table['Production [kWh/kW]'] = energy | ||
| table['Capital cost [$/kW]'] = cap_cost | ||
| table['O&M [$/kW]'] = fixed_om | ||
| table.index.name = 'Year' | ||
| table | ||
| 
     | 
||
| # %% | ||
| # Get LCOE | ||
| 
     | 
||
| my_lcoe = financial.lcoe(production=energy, cap_cost=cap_cost, | ||
| fixed_om=fixed_om) | ||
| print('LCOE = ' + str(my_lcoe) + str(' cents/kWh')) | ||
  
    
      This file contains hidden or 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,13 @@ | ||
| .. currentmodule:: pvlib | ||
| 
     | 
||
| Financial | ||
| ========= | ||
| 
     | 
||
| .. autosummary:: | ||
| :toctree: generated/ | ||
| 
     | 
||
| financial.lcoe | ||
| financial.crf | ||
| financial.nominal_to_real | ||
| financial.real_to_nominal | ||
| financial.wacc | 
  
    
      This file contains hidden or 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 | 
|---|---|---|
| 
          
            
          
           | 
    @@ -20,3 +20,4 @@ API reference | |
| bifacial | ||
| scaling | ||
| location | ||
| financial | ||
  
    
      This file contains hidden or 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
    
  
  
    
              
  
    
      This file contains hidden or 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
    
  
  
    
              
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.