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

Capex and One-time Cashflows #50

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 20 additions & 7 deletions src/DispatchManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def extract_variables(self, raven, raven_dict):
name = self.naming_template['comp capacity'].format(comp=comp.name)
update_capacity = raven_dict.get(name) # TODO is this ever not provided?
comp.set_capacity(update_capacity)
pass_vars[f'{comp.name}_capacity'] = update_capacity
# TODO other case, component properties

# load ARMA signals
Expand Down Expand Up @@ -294,6 +295,7 @@ def _do_cashflow(self, meta, all_dispatch, all_structure, project_life, interp_y
# TODO we assume Capex and Recurring Year do not depend on the Activity
if cf_cf.type == 'Capex':
# Capex cfs should only be constructed in the first year of the project life
# FIXME is this doing capex once per segment, or once per life?
if year == 0:
params = heron_cf.calculate_params(specific_meta) # a, D, Dp, x, cost
cf_params = {'name': cf_cf.name,
Expand All @@ -309,15 +311,23 @@ def _do_cashflow(self, meta, all_dispatch, all_structure, project_life, interp_y
# hot swap this cashflow into the final_comp, I think ...
# I believe we can do this because Capex are division-independent? Can we just do
# it once instead of once per division?
final_comp._cash_flows[f] = cf_cf
# else: nothing to do if Capex and year != 0
final_comp._cashFlows[f] = cf_cf
# depreciators
# FIXME do we need to know alpha, drivers first??
if heron_cf._depreciate:
cf_cf.setAmortization('MACRS', heron_cf._depreciate)
deprs = cf_comp._createDepreciation(cf_cf)
final_comp._cashFlows.extend(deprs)
print(f'DEBUGG ... ... ... ... ... yearly contribution: {params["cost"]: 1.9e} ...')
else: # nothing to do if Capex and year != 0
print(f'DEBUGG ... ... ... ... ... yearly contribution: 0 ...')
elif cf_cf.type == 'Recurring':
# yearly recurring only need setting up once per year
if heron_cf.get_period() == 'year':
params = heron_cf.calculate_params(specific_meta) # a, D, Dp, x, cost
contrib = cf_cf._yearly_cashflow
contrib = params['cost'] # cf_cf._yearlyCashflow
print(f'DEBUGG ... ... ... ... ... yearly contribution: {contrib: 1.9e} ...')
final_cf._yearly_cashflow[year + 1] += contrib # FIXME multiplicity? -> should not apply to Recurring.Yearly
final_cf._yearlyCashflow[year + 1] += contrib # FIXME multiplicity? -> should not apply to Recurring.Yearly
# hourly recurring need iteration over time
elif heron_cf.get_period() == 'hour':
for t, time in enumerate(times):
Expand Down Expand Up @@ -356,7 +366,10 @@ def _do_cashflow(self, meta, all_dispatch, all_structure, project_life, interp_y
print(f' ... ... cf {cf.name} ...')
print(f' ... ... ... D', cf._driver)
print(f' ... ... ... a', cf._alpha)
print(f' ... ... ... a', cf._yearlyCashflow)
print(f' ... ... ... Dp', cf._reference)
print(f' ... ... ... x', cf._scale)
if hasattr(cf, '_yearlyCashflow'):
print(f' ... ... ... hourly', cf._yearlyCashflow)

cf_metrics = CashFlow_run(final_settings, list(final_components.values()), raven_vars)

Expand Down Expand Up @@ -413,10 +426,10 @@ def _build_econ_objects(self, heron_case, heron_components, project_life):
}
cf_cf.setParams(cf_cf_params)
cf_cf.initParams(project_life)
elif heron_cf._type == 'one_time': # FIXME protected access
elif heron_cf._type == 'one-time': # FIXME protected access
cf_cf = CashFlows.Capex()
cf_cf.name = cf_name
cf_cf.init_params(cf_comp.get_lifetime())
cf_cf.initParams(cf_comp.getLifetime())
# alpha, driver aren't known yet, so set those later
else:
raise NotImplementedError(f'Unknown HERON CashFlow Type: {heron_cf._type}')
Expand Down
30 changes: 30 additions & 0 deletions tests/integration_tests/cashflows/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2020, Battelle Energy Alliance, LLC
# ALL RIGHTS RESERVED
"""
Implements transfer functions
"""

def capacity(data, meta):
"""
return unit capacity
@ In, data, dict, data requeset
@ In, meta, dict, state information
@ Out, data, dict, filled data
@ Out, meta, dict, state information
"""
c = float(meta['HERON']['RAVEN_vars']['source_capacity'])
data = {'driver': c}
return data, meta

def activity(data, meta):
"""
return usage of resource "a"
@ In, data, dict, data requeset
@ In, meta, dict, state information
@ Out, data, dict, filled data
@ Out, meta, dict, state information
"""
a = meta['HERON']['activity']['a']
data = {'driver': a}
return data, meta

3 changes: 3 additions & 0 deletions tests/integration_tests/cashflows/gold/Runs_o/sweep.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source_capacity,sink_capacity,mean_NPV,std_NPV,med_NPV,max_NPV,min_NPV,perc_5_NPV,perc_95_NPV,samp_NPV,var_NPV,prefix,ProbabilityWeight-source_capacity,PointProbability,ProbabilityWeight
1.0,-2.0,3894.83025031,0.0,3894.83025031,3894.83025031,3894.83025031,3894.83025031,3894.83025031,3.0,0.0,1,0.5,1.0,0.5
2.0,-2.0,7791.81176253,1.11389897155e-12,7791.81176253,7791.81176253,7791.81176253,7791.81176253,7791.81176253,3.0,1.24077091883e-24,2,0.5,1.0,0.5
111 changes: 111 additions & 0 deletions tests/integration_tests/cashflows/heron_input.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<HERON>
<TestInfo>
<name>Cashflows</name>
<author>talbpaul</author>
<created>2020-10-16</created>
<description>
Tests various kinds of cashflows
</description>
<classesTested>HERON</classesTested>
</TestInfo>

<Case name="Runs">
<mode>sweep</mode>
<num_arma_samples>3</num_arma_samples>
<time_discretization>
<time_variable>Time</time_variable>
<end_time>2</end_time>
<num_steps>21</num_steps>
</time_discretization>
<economics>
<ProjectTime>30</ProjectTime>
<DiscountRate>0.08</DiscountRate>
<tax>0.0</tax>
<inflation>0.03</inflation>
<verbosity>50</verbosity>
</economics>
<dispatcher>
<pyomo/>
</dispatcher>
</Case>

<Components>
<Component name="source">
<produces resource="a" dispatch="fixed">
<capacity resource="a">
<sweep_values>1, 2</sweep_values>
</capacity>
</produces>
<economics>
<lifetime>10</lifetime>
<CashFlow name="capex" type="one-time" taxable="False" inflation="none" mult_target="False">
<driver>
<Function method="capacity">functions</Function>
</driver>
<reference_price>
<fixed_value>10000.0</fixed_value>
<multiplier>-1</multiplier>
</reference_price>
<reference_driver>
<fixed_value>10.0</fixed_value>
</reference_driver>
<scaling_factor_x>
<fixed_value>0.999</fixed_value>
</scaling_factor_x>
<depreciate>5</depreciate>
</CashFlow>
<CashFlow name="FOM" type="repeating" period='year' taxable="False" inflation="none" mult_target="False">
<driver>
<Function method="capacity">functions</Function>
</driver>
<reference_price>
<fixed_value>100.0</fixed_value>
<multiplier>-1</multiplier>
</reference_price>
<reference_driver>
<fixed_value>10.0</fixed_value>
</reference_driver>
<scaling_factor_x>
<fixed_value>0.999</fixed_value>
</scaling_factor_x>
</CashFlow>
<CashFlow name="VOM" type="repeating" taxable="False" inflation="none" mult_target="False">
<driver>
<Function method="activity">functions</Function>
</driver>
<reference_price>
<fixed_value>-1</fixed_value>
</reference_price>
</CashFlow>
</economics>
</Component>

<Component name="sink">
<demands resource="a" dispatch="independent">
<capacity>
<fixed_value>-2</fixed_value>
</capacity>
</demands>
<economics>
<lifetime>30</lifetime>
<CashFlow name="sales" type="repeating" taxable="False" inflation="none" mult_target="False">
<driver>
<Function method="activity">functions</Function>
</driver>
<reference_price>
<fixed_value>10.0</fixed_value>
<multiplier>-3.14</multiplier>
</reference_price>
</CashFlow>
</economics>
</Component>
</Components>

<DataGenerators>
<ARMA name='flex' variable="Signal">../ARMA/Sine/arma.pk</ARMA>
<Function name="functions">functions.py</Function>
</DataGenerators>
</HERON>



14 changes: 14 additions & 0 deletions tests/integration_tests/cashflows/tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[Tests]
[./Cashflows]
type = HeronIntegration
input = heron_input.xml
# prereq = SineArma
[./csv]
type = OrderedCSV
output = 'Runs_o/sweep.csv'
zero_threshold = 1e-6
rel_err = 1e-6
[../]
[../]

[]
2 changes: 1 addition & 1 deletion tests/integration_tests/production_flex/heron_input.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<HERON>
<TestInfo>
<name>production</name>
<name>ProductionFlex</name>
<author>talbpaul</author>
<created>2020-06-15</created>
<description>
Expand Down