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

Features/integrate stochastic programming #809

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions src/oemof/solph/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ._energy_system import EnergySystem
from ._groupings import GROUPINGS
from ._models import Model
from ._models import StochasticModel
from ._options import Investment
from ._options import NonConvex
from ._plumbing import sequence
Expand Down
38 changes: 38 additions & 0 deletions src/oemof/solph/_groupings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,46 @@ def _nonconvex_grouping(stf):
constant_key=NonConvexFlowBlock, filter=_nonconvex_grouping
)

def _stochastic_investflow_grouping(stf):
if hasattr(stf[2], "investment"):
if stf[2].investment is not None:
if stf[2].investment.firststage == True:
return True
else:
return False

stochastic_investflow_grouping = groupings.FlowsWithNodes(
constant_key="FirstStageInvestFlows", filter=_stochastic_investflow_grouping
)

def _stochastic_investnode_grouping(stf):
if hasattr(stf[0], "investment"):
if stf[0].investment is not None:
if stf[0].investment.firststage == True:
return True
else:
return False

stochastic_investnode_grouping = groupings.FlowsWithNodes(
constant_key="FirstStageInvestNodes", filter=_stochastic_investnode_grouping
)

def _stochastic_flow_grouping(stf):
if hasattr(stf[2], "firststage"):
return True
else:
return False

stochastic_flow_grouping = groupings.FlowsWithNodes(
constant_key="FirstStageFlows", filter=_stochastic_flow_grouping
)



GROUPINGS = [
stochastic_investflow_grouping,
stochastic_investnode_grouping,
stochastic_flow_grouping,
constraint_grouping,
investment_flow_grouping,
standard_flow_grouping,
Expand Down
96 changes: 95 additions & 1 deletion src/oemof/solph/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@

from pyomo import environ as po
from pyomo.core.plugins.transform.relax_integrality import RelaxIntegrality
from pyomo.core.expr import current as EXPR
from pyomo.opt import SolverFactory

from oemof.solph import processing
from oemof.solph._plumbing import sequence
from oemof.solph.buses._bus import BusBlock
from oemof.solph.components._transformer import TransformerBlock
from oemof.solph.flows._flow import FlowBlock
from oemof.solph.flows._flow import StochasticFlowBlock
from oemof.solph.flows._investment_flow import InvestmentFlowBlock
from oemof.solph.flows._investment_flow import StochasticInvestmentFlowBlock
from oemof.solph.flows._non_convex_flow import NonConvexFlowBlock


Expand Down Expand Up @@ -164,7 +167,6 @@ def _add_objective(self, sense=po.minimize, update=False):
for block in self.component_data_objects():
if hasattr(block, "_objective_expression"):
expr += block._objective_expression()

self.objective = po.Objective(sense=sense, expr=expr)

def receive_duals(self):
Expand Down Expand Up @@ -366,3 +368,95 @@ def _add_parent_block_variables(self):
if (o, i) in self.UNIDIRECTIONAL_FLOWS:
for t in self.TIMESTEPS:
self.flow[o, i, t].setlb(0)


class StochasticModel(Model):
"""

"""
def __init__(self, energysystem, **kwargs):
super().__init__(energysystem, **kwargs)

def _add_stage_sets(self):
"""
"""

if self.es.groups.get("FirstStageFlows"):
initialize = [(i,o) for i,o,f in self.es.groups.get("FirstStageFlows")]
else:
initialize = []

self.FIRSTSTAGE_FLOWS = po.Set(
initialize=initialize,
ordered=True,
dimen=2,
within=self.FLOWS,
)


if self.es.groups.get("FirstStageInvestFlows"):
initialize = [(i,o) for i,o,f in self.es.groups.get("FirstStageInvestFlows")]
else:
initialize = []
self.FIRSTSTAGE_INVESTFLOWS = po.Set(
initialize=[
(i,o) for i,o,f in self.es.groups.get("FirstStageInvestFlows")],
ordered=True,
dimen=2,
within=self.FLOWS,
)

self.FIRSTSTAGE_INVESTNODES = po.Set(
initialize=[
i for i,o,f in self.es.groups.get("FirstStageInvestNodes")],
ordered=True,
dimen=1,
)

def get_firststage_vars(self):
"""
"""
first_stage_vars = [
var for var in
EXPR.identify_variables(self.FlowBlock.firststage_variable_costs)
]
first_stage_vars += [
var for var in
EXPR.identify_variables(self.FlowBlock.firststage_gradient_costs)
]
first_stage_vars += [
var for var in
EXPR.identify_variables(self.InvestmentFlowBlock.firststage_investment_costs)
]
first_stage_vars += [
var for var in
EXPR.identify_variables(self.GenericInvestmentStorageBlock.firststage_investment_costs)
]
return first_stage_vars

def _construct(self):
""" """
self._add_parent_block_sets()
self._add_stage_sets()

self._add_parent_block_variables()
self._add_child_blocks()

self._add_objective()

self.firststage_vars = self.get_firststage_vars()

def _add_objective(self, sense=po.minimize, update=False):
"""
"""
if update:
self.del_component("objective")

expr = 0

for block in self.component_data_objects():
if hasattr(block, "_stochastic_objective_expression"):
expr += block._stochastic_objective_expression()
elif hasattr(block, "_objective_expression"):
expr += block._objective_expression()
self.objective = po.Objective(sense=sense, expr=expr)
35 changes: 35 additions & 0 deletions src/oemof/solph/components/_generic_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,38 @@ def _objective_expression(self):
self.investment_costs = Expression(expr=investment_costs)

return investment_costs

def _stochastic_objective_expression(self):
"""Objective expression with fixed and investement costs."""

m = self.parent_block()

if not hasattr(self, "INVESTSTORAGES"):
return 0

investment_costs = 0
firststage_investment_costs = 0

for n in self.CONVEX_INVESTSTORAGES - m.FIRSTSTAGE_INVESTNODES:
investment_costs += self.invest[n] * n.investment.ep_costs
for n in self.NON_CONVEX_INVESTSTORAGES - m.FIRSTSTAGE_INVESTNODES:
investment_costs += (
self.invest[n] * n.investment.ep_costs
+ self.invest_status[n] * n.investment.offset
)
self.investment_costs = Expression(expr=investment_costs)

for n in self.CONVEX_INVESTSTORAGES:
if n in m.FIRSTSTAGE_INVESTNODES:
firststage_investment_costs += self.invest[n] * n.investment.ep_costs

for n in self.NON_CONVEX_INVESTSTORAGES:
if n in m.FIRSTSTAGE_INVESTNODES:
firststage_investment_costs += (
self.invest[n] * n.investment.ep_costs
+ self.invest_status[n] * n.investment.offset
)

self.firststage_investment_costs = Expression(expr=firststage_investment_costs)

return self.investment_costs + self.firststage_investment_costs
45 changes: 45 additions & 0 deletions src/oemof/solph/components/experimental/_ancillary_services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-

"""
In-development component for ancillary services demand

SPDX-FileCopyrightText: Ekaterina Zolotarevskaia (e-zolotarevskaya)

SPDX-License-Identifier: MIT

"""
from oemof.solph.components._sink import Sink
import random

class AncillaryServices(Sink):
"""
request
timeindex
price
"""
def __init__(self, request, timeindex, price):
self.request = request # timeseries of ancillary services request
self.timeindex = timeindex
self.price = price

#julia-style draft
def createAncServScen(self,nominal_value,request_number, timeindex):
s_xi = random.choice([1,-1])
recovery_time = 12
if s_xi == 1:
#Sink
else:
#Source
t_xi = [0 for i in range(request_number)]
for i in range(request_number):
t_xi[i] = random.randrange(24)
flow = [0. for i in range(recovery_time)]
for t in t_xi:
flow[t] = nominal_value


"""
constraint (model or model components/constraints/objectives, stage_index, anc_nominal_value, request_number = 1):
create_scenario function (oemof model, realization of stoc vars)

"""
Loading