idaholab / TEAL

TEAL is a financial performance calculator plugin for the RAVEN code, framework, resolving around the computation of Net Present Value and associated financial metrics.
Apache License 2.0
9 stars 21 forks source link

[DEFECT] Code crashes when MACRS and lifetime are equal #53

Open mgarrouste opened 2 years ago

mgarrouste commented 2 years ago

Defect Description

Describe the defect

What did you expect to see happen?

I expected the HERON model to run

What did you see instead?

An exception was thrown because 2 arrays were incompatible in size

Do you have a suggested fix for the development team?

Describe how to Reproduce Steps to reproduce the behavior:

  1. Write a HERON input with a component with a lifetime of 20 years and a MACRS depreciation schedule of 20 years too
  2. Run HERON
  3. Run RAVEN

Screenshots and Input Files Please attach the input file(s) that generate this error. The simpler the input, the faster we can find the issue.

Platform (please complete the following information):


For Change Control Board: Issue Review

This review should occur before any development is performed as a response to this issue.


For Change Control Board: Issue Closure

This review should occur when the issue is imminently going to be closed.

dylanjm commented 2 years ago

@mgarrouste I can't replicate your issue by only changing the lifetime and depreciation schedule to the same number. Can you post a simple reproducible example/input file? Thanks

EDIT: Also please include the full stack trace for the error that was thrown.

mgarrouste commented 2 years ago

Here is my heron input, I changed the lifetime of the HTSE component from 30 years to 20 and now it crashes. The inner output file is attached as well as the console output.

<HERON>
  <Case name="HTSE">
    <mode>opt</mode>
    <debug></debug>
    <verbosity>debug</verbosity>
    <num_arma_samples>3</num_arma_samples>
    <time_discretization>
      <time_variable>hour</time_variable>
      <year_variable>Year</year_variable>
      <end_time>23</end_time>
      <num_steps>24</num_steps>
    </time_discretization>
    <economics>
      <ProjectTime>3</ProjectTime>
      <DiscountRate>0.08</DiscountRate>
      <tax>0.1</tax>
      <inflation>0.00</inflation>
      <verbosity>50</verbosity>
    </economics>
    <dispatcher>
      <pyomo><debug_mode>True</debug_mode></pyomo>
    </dispatcher>
    <optimization_settings>
      <metric>expectedValue</metric>
      <type>max</type>
      <persistence>10</persistence>
    </optimization_settings>
  </Case>

  <Components>
  <!-- PRODUCTION Components -->
    <Component name='turbine'>
      <produces resource='electricity' dispatch='fixed'>
        <capacity resource='electricity'>
          <opt_bounds debug_value="124.9e3">1e3,750e3</opt_bounds> <!-- kWe -->
          <!--<sweep_values debug_value="100e3">10e3,500e3</sweep_values>-->
        </capacity>
      </produces>
      <economics>
        <lifetime>30</lifetime>
      </economics>
    </Component>

    <Component name='htse'>
      <produces resource='h2' dispatch='independent'>
        <consumes>electricity</consumes>
        <capacity resource ='electricity'>
          <opt_bounds debug_value="-100e3">-750e3,0</opt_bounds> <!-- kW -->
        </capacity>
        <transfer>
          <linear>
            <rate resource='electricity'>-1</rate>
            <rate resource='h2'>1</rate>
            <!-- from 39.8kWh/kg electricity consumption for H2 prod-->
          </linear>
        </transfer>
      </produces>
      <economics>
        <lifetime>20</lifetime>
        <CashFlow name="htse_capex" type="one-time" taxable="True" inflation="None" mult_target="False">
          <driver>
            <variable>htse_capacity</variable>
          </driver>
          <reference_price>
            <fixed_value>-703</fixed_value>
            <!-- $703/kW-dc -->
          </reference_price>
          <depreciate>20</depreciate>
          <!-- 20 years MACRS -->
        </CashFlow>
        <CashFlow name="htse_fom" type="repeating" period="year" taxable="True" inflation="None" mult_target="False">
          <driver>
            <variable>htse_capacity</variable>
          </driver>
          <reference_price>
            <fixed_value>-32.64</fixed_value>
            <!-- $32.64/kW-dc-year -->
          </reference_price>
        </CashFlow>
        <CashFlow name="htse_vom" type="repeating" taxable="True" inflation="None" mult_target="False">
          <driver>
            <activity>electricity</activity>
          </driver>
          <reference_price>
            <fixed_value>-3.41e-3</fixed_value>
            <!-- $3.41/MWh-dc -->
          </reference_price>
        </CashFlow>
        <CashFlow name="elec_cap_market" type="one-time" taxable="True" inflation="None" mult_target="False">
          <driver>
            <variable>htse_capacity</variable>
          </driver>
          <reference_price>
            <fixed_value>-30e-3</fixed_value>
            <!-- $30/MW, sweep values later to see the influence on the system -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

    <Component name='ft'>
      <!-- Component for FT, RWGS and refinery -->
      <produces resource='naphta,diesel,jet_fuel' dispatch='independent'>
        <consumes>h2, co2</consumes>
        <capacity resource='h2'>
          <opt_bounds debug_value="-100e3">-750e3,0</opt_bounds>
          <!-- kg/h -->
        </capacity>
        <transfer>
          <linear>
            <!-- TRying with kg/h units for mass flows -->
            <rate resource='h2'>-1.06</rate>
            <rate resource='co2'>-6.58</rate>
            <rate resource='naphta'>0.733</rate>
            <rate resource='jet_fuel'>0.888</rate>
            <rate resource='diesel'>0.492</rate>
          </linear>
        </transfer>
      </produces>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name="ft_capex" type="one-time" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-378878417</fixed_value>
            <!-- TCI -->
          </reference_price>
          <depreciate>20</depreciate>
          <!-- 20 years MACRS -->
        </CashFlow>
        <CashFlow name="ft_fom" type="repeating" period="year" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-20156141</fixed_value>
            <!-- Total Fixed Operating Costs -->
          </reference_price>
        </CashFlow>
        <CashFlow name="ft_vom" type="repeating" period="year" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-7085933</fixed_value>
            <!-- Variable Operating Costs excluding feedstock and electricity costs -->
          </reference_price>
        </CashFlow>
        <CashFlow name="elec_cap_market" type="one-time" taxable="True" inflation="None" mult_target="False">
          <driver>
            <variable>ft_capacity</variable>
          </driver>
          <reference_price>
            <fixed_value>-30e-3</fixed_value>
            <!-- $30/MW, sweep values later to see the influence on the system -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

    <Component name='ft_elec_consumption'>
      <demands resource='electricity' dispatch='fixed'>
        <capacity>
          <fixed_value>-14.9e3</fixed_value>
          <!-- FT needs 14.9MWe no matter what level of fuel products' production -->
        </capacity>
      </demands>
      <economics>
        <lifetime>1</lifetime>
      </economics>
    </Component>

    <Component name='CO2_source'>
      <produces resource='co2' dispatch='independent'>
        <capacity resource='co2'>
          <opt_bounds>0,1e50</opt_bounds>
          <!-- From Arg. March 2022, CO2 flow to FT is 1580 MT/day = 65.8e3 kg/h-->
          <!-- Can get as much CO2 as needed -->
        </capacity>
      </produces>
      <economics>
        <!-- Just copied numbers from FT process for now -->
        <lifetime>30</lifetime>
        <CashFlow name="CO2_source_capex" type="one-time" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-378878417</fixed_value>
            <!-- TCI -->
          </reference_price>
          <depreciate>20</depreciate>
          <!-- 20 years MACRS -->
        </CashFlow>
        <CashFlow name="CO2_source_fom" type="repeating" period="year" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-20156141</fixed_value>
            <!-- Total Fixed Operating Costs -->
          </reference_price>
        </CashFlow>
        <CashFlow name="CO2_source_vom" type="repeating" period="year" taxable="True" inflation="None" mult_target="False">
          <driver>
            <fixed_value>1</fixed_value>
          </driver>
          <reference_price>
            <fixed_value>-7085933</fixed_value>
            <!-- Variable Operating Costs excluding feedstock and electricity costs -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

  <!-- MARKETS Components -->
    <Component name='elec_market'>
      <demands resource='electricity' dispatch='dependent'>
        <capacity>
          <fixed_value>-1e200</fixed_value> 
          <!-- Can sell infinite amount of electricity to the market -->
        </capacity>
      </demands>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name='e_sales' type='repeating' taxable='True' inflation='none' mult_target='False'>
          <driver>
            <activity>electricity</activity>
            <multiplier>-1</multiplier>
          </driver>
          <reference_price>
            <fixed_value>0</fixed_value>
            <!-- Electricity is worth nothing so nothing should go to the grid -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

    <Component name='naphta_market'>
      <demands resource='naphta' dispatch='dependent'>
        <capacity>
          <fixed_value>-1e200</fixed_value>
        </capacity>
      </demands>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name='naphta_sales' type='repeating' taxable='True' inflation='none' mult_target='False'>
          <driver>
            <activity>naphta</activity>
            <multiplier>-1</multiplier>
          </driver>
          <reference_price>
            <fixed_value>1e4</fixed_value>
            <!-- $/kg -->
            <!-- Normal price should be around $1000/MT = $1/kg -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

    <Component name='jet_fuel_market'>
      <demands resource='jet_fuel' dispatch='dependent'>
        <capacity>
          <fixed_value>-1e200</fixed_value>
        </capacity>
      </demands>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name='jet_fuel_sales' type='repeating' taxable='True' inflation='none' mult_target='False'>
          <driver>
            <activity>jet_fuel</activity>
            <multiplier>-1</multiplier>
          </driver>
          <reference_price>
            <fixed_value>1e4</fixed_value>
            <!-- $/kg -->
            <!-- Normal price should be around $1300/MT = $1.3/kg -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

    <Component name='diesel_market'>
      <demands resource='diesel' dispatch='dependent'>
        <capacity>
          <fixed_value>-1e200</fixed_value>
        </capacity>
      </demands>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name='diesel_sales' type='repeating' taxable='True' inflation='none' mult_target='False'>
          <driver>
            <activity>diesel</activity>
            <multiplier>-1</multiplier>
          </driver>
          <reference_price>
            <fixed_value>1e4</fixed_value>
            <!-- $/kg -->
            <!-- Normal price should be around $25000/MT = $25/kg 
            (computed from $5.6/gal) -->
          </reference_price>
        </CashFlow>
      </economics>
    </Component>

  <!-- STORAGE Components -->
    <Component name='h2_storage'>
      <stores resource="h2" dispatch="independent">
        <capacity resource='h2'>
          <opt_bounds>0,200e3</opt_bounds>
        </capacity>
        <initial_stored>
          <fixed_value>0</fixed_value>
        </initial_stored>
        <RTE>0.9</RTE>
        <!-- Need to look up this value -->
      </stores>
      <economics>
        <lifetime>30</lifetime>
        <CashFlow name='h2_storage_capex' inflation="none" mult_target="False" taxable="True" type="one-time">
          <driver>
            <variable>h2_storage_capacity</variable>
          </driver>
          <reference_price>
            <fixed_value>-500</fixed_value>
            <!-- CApex cost of $500/kg-H2 -->
          </reference_price>
          <depreciate>15</depreciate>
        </CashFlow>
      </economics>
    </Component>

  </Components>

<DataGenerators>
  <!-- ARMA from PJM, Jakub and Yuscheng trained it -->
    <ARMA name='price' variable="price">../../train/Output_2018_2021_to2045_presvInpCDF_0_1_F1095_F168/arma.pk</ARMA>
</DataGenerators>

</HERON>

out~inner.txt out~outer.txt

dylanjm commented 2 years ago

I've pinpointed where the error in the code is coming from.

In Amortization.py the way the alpha array is populated can lead to inconsistent sizing when the depreciation schedule is the same length.

def amortize(scheme, plan, startValue, componentLife):
  """
    return the amortization plan
    @ In, scheme, str, 'macrs' or 'custom'
    @ In, plan, list or array like, list of provided MACRS values
    @ In, startValue, float, the given initial Capex value
    @ In, componentLife, int, the life of component
    @ Out, alpha, numpy.array, array of alpha values for given scheme
  """
  alpha = np.zeros(componentLife + 1, dtype=float)
  lscheme = scheme.lower()
  if lscheme == 'macrs':
    ys = plan[0]
    pcts = MACRS.get(ys, None)
    if pcts is None:
      raise IOError('Provided MACRS "{}" is not allowed.'.format(ys))
    alpha[1:len(pcts)+1] = pcts * startValue
  elif lscheme == 'custom':
    alpha[1:len(plan)+1] = np.asarray(plan)/100. * startValue
  else:
    raise NotImplementedError('Amortization scheme "{}" not yet implemented.'.format(scheme))
  return alpha
dylanjm commented 2 years ago

We can fix this easily by adding an additional alpha value when componentLife == plan[0] but this may be a question for @worseliz or @AaronEpiney.

Would it make sense to use a depreciation schedule of '20' when the lifetime of the component is '20'?

mgarrouste commented 2 years ago

I have a case where I am modelling an High Temperature Steam Electrolysis Process and the report about the costs assumes a 20 years project duration as well as a 20 years MACRS depreciation schedule

dylanjm commented 2 years ago

@mgarrouste Does the HTSE have an assumed lifetime of 20 years too? Or just a project time of 20 years?

alfoa commented 11 months ago

@dylanjm @worseliz @wangcj05 @AaronEpiney @GabrielSoto-INL I experience the same issue.