Skip to content

Commit

Permalink
Working PMH for now...
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjm committed Jan 17, 2024
1 parent 7596f46 commit f9c67eb
Showing 1 changed file with 107 additions and 0 deletions.
107 changes: 107 additions & 0 deletions src/dispatch/PyomoModelHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

class PyomoModelHandler:

_eps = 1e-9

def __init__(self, time, time_offset, case, components, resources, initial_storage, meta) -> None:
self.time = time
self.time_offset = time_offset
Expand Down Expand Up @@ -423,6 +425,111 @@ def _create_objective(self):
rule = lambda mod: prl.cashflow_rule(self._compute_cashflows, self.meta, mod)
self.model.obj = pyo.Objective(rule=rule, sense=pyo.maximize)

def _compute_cashflows(self, components, activity, times, meta, state_args=None, time_offset=0):
"""
Method to compute CashFlow evaluations given components and their activity.
@ In, components, list, HERON components whose cashflows should be evaluated
@ In, activity, DispatchState instance, activity by component/resources/time
@ In, times, np.array(float), time values to evaluate; may be length 1 or longer
@ In, meta, dict, additional info to be passed through to functional evaluations
@ In, state_args, dict, optional, additional arguments to pass while getting activity state
@ In, time_offset, int, optional, increase time index tracker by this value if provided
@ Out, total, float, total cashflows for given components
"""
if state_args is None:
state_args = {}

if meta['HERON']['Case'].use_levelized_inner:
total = self._compute_levelized_cashflows(components, activity, times, meta, state_args, time_offset)
return total

total = 0
specific_meta = dict(meta) # TODO what level of copying do we need here?
resource_indexer = meta['HERON']['resource_indexer']

#print('DEBUGG computing cashflows!')
for comp in components:
#print(f'DEBUGG ... comp {comp.name}')
specific_meta['HERON']['component'] = comp
comp_subtotal = 0
for t, time in enumerate(times):
#print(f'DEBUGG ... ... time {t}')
# NOTE care here to assure that pyomo-indexed variables work here too
specific_activity = {}
for tracker in comp.get_tracking_vars():
specific_activity[tracker] = {}
for resource in resource_indexer[comp]:
specific_activity[tracker][resource] = activity.get_activity(comp, tracker, resource, time, **state_args)
specific_meta['HERON']['time_index'] = t + time_offset
specific_meta['HERON']['time_value'] = time
cfs = comp.get_state_cost(specific_activity, specific_meta, marginal=True)
time_subtotal = sum(cfs.values())
comp_subtotal += time_subtotal
total += comp_subtotal
return total

def _compute_levelized_cashflows(self, components, activity, times, meta, state_args=None, time_offset=0):
"""
Method to compute CashFlow evaluations given components and their activity.
@ In, components, list, HERON components whose cashflows should be evaluated
@ In, activity, DispatchState instance, activity by component/resources/time
@ In, times, np.array(float), time values to evaluate; may be length 1 or longer
@ In, meta, dict, additional info to be passed through to functional evaluations
@ In, state_args, dict, optional, additional arguments to pass while getting activity state
@ In, time_offset, int, optional, increase time index tracker by this value if provided
@ Out, total, float, total cashflows for given components
"""
total = 0
specific_meta = dict(meta) # TODO what level of copying do we need here?
resource_indexer = meta['HERON']['resource_indexer']

# How does this work?
# The general equation looks like:
#
# SUM(Non-Multiplied Terms) + x * SUM(Multiplied Terms) = Target
#
# and we are solving for `x`. Target is 0 by default. Terms here are marginal cashflows.
# Summations here occur over: components, time steps, tracking variables, and resources.
# Typically, there is only 1 multiplied term/cash flow.

multiplied = 0
non_multiplied = 0

for comp in components:
specific_meta['HERON']['component'] = comp
multiplied_comp = 0
non_multiplied_comp = 0
for t, time in enumerate(times):
# NOTE care here to assure that pyomo-indexed variables work here too
specific_activity = {}
for tracker in comp.get_tracking_vars():
specific_activity[tracker] = {}
for resource in resource_indexer[comp]:
specific_activity[tracker][resource] = activity.get_activity(comp, tracker, resource, time, **state_args)
specific_meta['HERON']['time_index'] = t + time_offset
specific_meta['HERON']['time_value'] = time
cfs = comp.get_state_cost(specific_activity, specific_meta, marginal=True)

# there is an assumption here that if a component has a levelized cost, marginal cashflow
# then it is the only marginal cashflow
if comp.levelized_meta:
for cf in comp.levelized_meta.keys():
lcf = cfs.pop(cf) # this should be ok as long as HERON init checks are successful
multiplied_comp += lcf
else:
time_subtotal = sum(cfs.values())
non_multiplied_comp += time_subtotal

multiplied += multiplied_comp
non_multiplied += non_multiplied_comp

# at this point, there should be a not None NPV Target
multiplied += self._eps
total = (meta['HERON']['Case'].npv_target - non_multiplied) / multiplied
total *= -1
return total





Expand Down

0 comments on commit f9c67eb

Please sign in to comment.