diff --git a/src/oemof/solph/components/_generic_storage.py b/src/oemof/solph/components/_generic_storage.py index ab8141789..578bd962c 100644 --- a/src/oemof/solph/components/_generic_storage.py +++ b/src/oemof/solph/components/_generic_storage.py @@ -563,7 +563,7 @@ def _balanced_storage_rule(block, n): self.STORAGES_BALANCED, rule=_balanced_storage_rule ) - def _power_coupled(block): + def _power_coupled(_): """ Rule definition for constraint to connect the input power and output power @@ -1215,7 +1215,7 @@ def _create(self, group=None): # ######################### Variables ################################ self.storage_content = Var( - self.INVESTSTORAGES, m.TIMESTEPS, within=NonNegativeReals + self.INVESTSTORAGES, m.TIMEPOINTS, within=NonNegativeReals ) def _storage_investvar_bound_rule(block, n, p): @@ -1272,8 +1272,6 @@ def _storage_investvar_bound_rule(block, n, p): i = {n: [i for i in n.inputs][0] for n in group} o = {n: [o for o in n.outputs][0] for n in group} - reduced_periods_timeindex = [(p, t) for (p, t) in m.TIMEINDEX if t > 0] - # Handle unit lifetimes def _total_storage_capacity_rule(block): """Rule definition for determining total installed @@ -1463,7 +1461,7 @@ def _old_storage_capacity_rule(block): self.old_rule_build = BuildAction(rule=_old_storage_capacity_rule) - def _initially_empty_rule(block): + def _initially_empty_rule(_): """Ensure storage to be empty initially""" for n in self.INVESTSTORAGES: expr = self.storage_content[n, 0] == 0 @@ -1494,7 +1492,9 @@ def _inv_storage_init_content_max_rule(block, n): def _inv_storage_init_content_fix_rule(block, n): """Constraint for a fixed initial storage capacity.""" - return block.init_content[n] == n.initial_storage_level * ( + return block.storage_content[ + n, 0 + ] == n.initial_storage_level * ( n.investment.existing + block.invest[n, 0] ) @@ -1503,44 +1503,15 @@ def _inv_storage_init_content_fix_rule(block, n): rule=_inv_storage_init_content_fix_rule, ) - def _storage_balance_first_rule(block, n): - """ - Rule definition for the storage balance of every storage n - for the first time step. - """ - expr = 0 - expr += block.storage_content[n, 0] - expr += ( - -block.init_content[n] - * (1 - n.loss_rate[0]) ** m.timeincrement[0] - ) - expr += ( - n.fixed_losses_relative[0] - * (n.investment.existing + self.invest[n, 0]) - * m.timeincrement[0] - ) - expr += n.fixed_losses_absolute[0] * m.timeincrement[0] - expr += ( - -m.flow[i[n], n, 0] * n.inflow_conversion_factor[0] - ) * m.timeincrement[0] - expr += ( - m.flow[n, o[n], 0] / n.outflow_conversion_factor[0] - ) * m.timeincrement[0] - return expr == 0 - - self.balance_first = Constraint( - self.INVESTSTORAGES, rule=_storage_balance_first_rule - ) - def _storage_balance_rule(block, n, p, t): """ - Rule definition for the storage balance of every storage n - for every time step but the first. + Rule definition for the storage balance of every storage n and + every timestep. """ expr = 0 - expr += block.storage_content[n, t] + expr += block.storage_content[n, t + 1] expr += ( - -block.storage_content[n, t - 1] + -block.storage_content[n, t] * (1 - n.loss_rate[t]) ** m.timeincrement[t] ) expr += ( @@ -1559,7 +1530,7 @@ def _storage_balance_rule(block, n, p, t): self.balance = Constraint( self.INVESTSTORAGES, - reduced_periods_timeindex, + m.TIMEINDEX, rule=_storage_balance_rule, ) @@ -1639,40 +1610,7 @@ def _storage_capacity_outflow_invest_rule(block): rule=_storage_capacity_outflow_invest_rule ) - def _max_storage_content_invest_rule(block, n, p, t): - """ - Rule definition for upper bound constraint for the - storage content. - """ - expr = ( - self.storage_content[n, t] - <= self.total[n, p] * n.max_storage_level[t] - ) - return expr - - self.max_storage_content = Constraint( - self.INVESTSTORAGES, - m.TIMEINDEX, - rule=_max_storage_content_invest_rule, - ) - - def _min_storage_content_invest_rule(block, n, p, t): - """ - Rule definition of lower bound constraint for the - storage content. - """ - expr = ( - self.storage_content[n, t] - >= self.total[n, p] * n.min_storage_level[t] - ) - return expr - - # Set the lower bound of the storage content if the attribute exists - self.min_storage_content = Constraint( - self.MIN_INVESTSTORAGES, - m.TIMEINDEX, - rule=_min_storage_content_invest_rule, - ) + self._add_storage_limit_constraints() def maximum_invest_limit(block, n, p): """ @@ -1746,6 +1684,79 @@ def _overall_minimum_investflow_rule(block): rule=_overall_minimum_investflow_rule ) + def _add_storage_limit_constraints(self): + m = self.parent_block() + if m.es.periods is None: + + def _max_storage_content_invest_rule(_, n, t): + """ + Rule definition for upper bound constraint for the + storage content. + """ + expr = ( + self.storage_content[n, t] + <= self.total[n, 0] * n.max_storage_level[t] + ) + return expr + + self.max_storage_content = Constraint( + self.INVESTSTORAGES, + m.TIMEPOINTS, + rule=_max_storage_content_invest_rule, + ) + + def _min_storage_content_invest_rule(_, n, t): + """ + Rule definition of lower bound constraint for the + storage content. + """ + expr = ( + self.storage_content[n, t] + >= self.total[n, 0] * n.min_storage_level[t] + ) + return expr + + self.min_storage_content = Constraint( + self.MIN_INVESTSTORAGES, + m.TIMEPOINTS, + rule=_min_storage_content_invest_rule, + ) + else: + + def _max_storage_content_invest_rule(_, n, p, t): + """ + Rule definition for upper bound constraint for the + storage content. + """ + expr = ( + self.storage_content[n, t] + <= self.total[n, p] * n.max_storage_level[t] + ) + return expr + + self.max_storage_content = Constraint( + self.INVESTSTORAGES, + m.TIMEINDEX, + rule=_max_storage_content_invest_rule, + ) + + def _min_storage_content_invest_rule(_, n, p, t): + """ + Rule definition of lower bound constraint for the + storage content. + """ + expr = ( + self.storage_content[n, t] + >= self.total[n, p] * n.min_storage_level[t] + ) + return expr + + self.min_storage_content = Constraint( + self.MIN_INVESTSTORAGES, + m.TIMEINDEX, + rule=_min_storage_content_invest_rule, + ) + def _objective_expression(self): """Objective expression with fixed and investment costs.""" m = self.parent_block() diff --git a/tests/test_scripts/test_solph/test_storage_investment/test_storage_investment.py b/tests/test_scripts/test_solph/test_storage_investment/test_storage_investment.py index e67bec253..7af43c441 100644 --- a/tests/test_scripts/test_solph/test_storage_investment/test_storage_investment.py +++ b/tests/test_scripts/test_solph/test_storage_investment/test_storage_investment.py @@ -157,7 +157,7 @@ def test_optimise_storage_size( es.dump() -def test_results_with_actual_dump(): +def test_results_with_recent_dump(): test_optimise_storage_size() energysystem = solph.EnergySystem() energysystem.restore() @@ -196,7 +196,7 @@ def test_results_with_actual_dump(): # Problem results assert meta["problem"]["Lower bound"] == 4.231675777e17 assert meta["problem"]["Upper bound"], 4.231675777e17 - assert meta["problem"]["Number of variables"] == 2807 + assert meta["problem"]["Number of variables"] == 2808 assert meta["problem"]["Number of constraints"] == 2808 assert meta["problem"]["Number of nonzeros"] == 1197 assert meta["problem"]["Number of objectives"] == 1