diff --git a/component/adapter.py b/component/adapter.py index 24468195159c5cd611eaac6a73ec6c27eeacfd14..b6297464da06afb16e3f27ddce6785314a35bf3f 100644 --- a/component/adapter.py +++ b/component/adapter.py @@ -29,6 +29,7 @@ from Model_Library.component.core import ( ComponentKind, ) from Model_Library.dynamics import Profile, resample, resample_variable +from Model_Library.optimization_model import VariableKind import pyomo.environ as pyo @@ -61,7 +62,10 @@ class AssetAdapter(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1", self.name + ".output_1"] + return [ + (self.name + ".input_1", VariableKind.INDEXED), + (self.name + ".output_1", VariableKind.INDEXED), + ] def _build_operational_model(self, d_block, o_block): input = pyo.Var(o_block.T, bounds=(0, None)) @@ -123,7 +127,10 @@ class MemberAdapter(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1", self.name + ".output_1"] + return [ + (self.name + ".input_1", VariableKind.INDEXED), + (self.name + ".output_1", VariableKind.INDEXED), + ] def _build_operational_model(self, d_block, o_block): input = pyo.Var(o_block.T, bounds=(0, None)) diff --git a/component/core.py b/component/core.py index a67777a38f8e3713de21ac68bc23ded1b4b07cb8..7fc39873da7e8663d0b927857353f183040aae0f 100644 --- a/component/core.py +++ b/component/core.py @@ -22,8 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from Model_Library.utility import design_annuity, operational_annuity from Model_Library.dynamics import resample +from Model_Library.utility import design_annuity, operational_annuity +from Model_Library.optimization_model import VariableKind from enum import Enum import json @@ -132,7 +133,7 @@ class AbstractComponent: if self.capacity is None: return [] else: - return [self.name + ".capacity"] + return [(self.name + ".capacity", VariableKind.UNINDEXED)] def operational_base_variable_names(self): pass @@ -325,7 +326,10 @@ class BaseBusBar(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1", self.name + ".output_1"] + return [ + (self.name + ".input_1", VariableKind.INDEXED), + (self.name + ".output_1", VariableKind.INDEXED), + ] def _build_operational_model(self, d_block, o_block): input = pyo.Var(o_block.T, bounds=(0, None)) @@ -379,7 +383,7 @@ class BaseComponent(AbstractComponent): dep_var_2 = self.conversion_2[1] if self.conversion_2 is not None else None self.operational_variables = [ - self.name + "." + var + (self.name + "." + var, VariableKind.INDEXED) for var in ["input_1", "input_2", "output_1", "output_2"] if var in [self.indep_var_1, self.indep_var_2, dep_var_1, dep_var_2] ] @@ -543,7 +547,7 @@ class BaseConsumption(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1"] + return [(self.name + ".input_1", VariableKind.INDEXED)] def _build_operational_model(self, d_block, o_block): input = pyo.Var(o_block.T, bounds=(0, None)) @@ -586,7 +590,7 @@ class BaseGeneration(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".output_1"] + return [(self.name + ".output_1", VariableKind.INDEXED)] def _build_operational_model(self, d_block, o_block): output = pyo.Var(o_block.T, bounds=(0, None)) @@ -655,7 +659,10 @@ class BaseGrid(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1", self.name + ".output_1"] + return [ + (self.name + ".input_1", VariableKind.INDEXED), + (self.name + ".output_1", VariableKind.INDEXED), + ] def _build_operational_model(self, d_block, o_block): input = pyo.Var(o_block.T, bounds=(0, None)) @@ -784,7 +791,11 @@ class BaseStorage(AbstractComponent): return match_kind and match_commodity def operational_base_variable_names(self): - return [self.name + ".input_1", self.name + ".output_1", self.name + ".energy"] + return [ + (self.name + ".input_1", VariableKind.INDEXED), + (self.name + ".output_1", VariableKind.INDEXED), + (self.name + ".energy", VariableKind.EXTENDED_INDEXED), + ] def _build_operational_model(self, d_block, o_block): capacity = d_block.component_dict[self.name + ".capacity"] diff --git a/component/electricity.py b/component/electricity.py index c738895bf6949b9d77b2ac42f7843befff0b45e0..15202c841dc4d5af10712116caa613c2012cbe65 100644 --- a/component/electricity.py +++ b/component/electricity.py @@ -32,6 +32,7 @@ from Model_Library.component.core import ( ComponentCommodity, ) from Model_Library.dynamics import resample +from Model_Library.optimization_model import VariableKind import json import pyomo.environ as pyo @@ -128,7 +129,7 @@ class PVGenerator(BaseComponent): self.noct = model["NOCT"] self.temperature_coefficient = model["temperature_coefficient"] - self.operational_variables = [self.name + ".output_1"] + self.operational_variables = [(self.name + ".output_1", VariableKind.INDEXED)] def _build_operational_model(self, d_block, o_block): if hasattr(self, "power_factors"): diff --git a/component/heat.py b/component/heat.py index ea51bd1c32a6efacc2103f6ee0af484f9f4cf15f..b841a5cc633abed1b16251bf76d48292463b51b6 100644 --- a/component/heat.py +++ b/component/heat.py @@ -30,6 +30,7 @@ from Model_Library.component.core import ( ComponentCommodity, ) from Model_Library.dynamics import resample +from Model_Library.optimization_model import VariableKind import pyomo.environ as pyo @@ -126,7 +127,7 @@ class SolarThermalCollector(BaseComponent): self.irradiance = resample(configuration["irradiance"], dynamic) def _setup_conversions(self, configuration): - self.operational_variables = [self.name + ".output_1"] + self.operational_variables = [(self.name + ".output_1", VariableKind.INDEXED)] def _build_operational_model_new(self, d_block, o_block): irradiance = resample(self.irradiance, o_block.dynamic).values diff --git a/optimization_model.py b/optimization_model.py index ecdc6e91a02116de6fa7ecc7678aeab8252302ea..31f2db652dda31c078e1d71b96b8b039fcc8185b 100644 --- a/optimization_model.py +++ b/optimization_model.py @@ -56,7 +56,6 @@ class OptimizationBlock: self.T_prime = self.block.T_prime self.component_dict = dict() - self.var_kinds = dict() self.objectives = dict() self.general_scaled_expression = [] self.blocks = dict() @@ -72,23 +71,9 @@ class OptimizationBlock: self.block.add_component(name, component.block) if isinstance(component, pyo.Var): self.component_dict[name] = component - if component.is_indexed() and component.index_set() == self.T: - self.var_kinds[name] = VariableKind.INDEXED - elif not component.is_indexed(): - self.var_kinds[name] = VariableKind.UNINDEXED - elif component.is_indexed() and component.index_set() == self.T_prime: - self.var_kinds[name] = VariableKind.EXTENDED_INDEXED - else: - raise ValueError( - "A variable to be added can only be unindexed or indexed over T or T_prime!" - ) elif isinstance(component, pyo.Expression): self.component_dict[name] = component elif isinstance(component, pyo.Param): - if ( - not component.is_indexed() - ): # Capacity can be a parameter -> fix is to add all pyo.Param and pyo.Expression to u_vars/i_vars/i_prime_vars - self.var_kinds[name] = VariableKind.UNINDEXED self.component_dict[name] = component def add_general_scaled_expression_term(self, term): @@ -110,7 +95,7 @@ class OptimizationBlock: return objectives def extract_result(self, var_names): - result = EntityResult(var_names, self.var_kinds, self.dynamic) + result = EntityResult(var_names, self.dynamic) result.extract_result(self) @@ -154,20 +139,19 @@ class OptimizationModel(OptimizationBlock): ) class EntityResult: - def __init__(self, var_names, var_kinds, dynamic): + def __init__(self, var_names, dynamic): n_u_vars = 0 n_i_vars = 0 n_i_prime_vars = 0 self.var_kinds = dict() - for var_name in var_names: - kind = var_kinds[var_name] - if kind == VariableKind.INDEXED: + for var_name, var_kind in var_names: + if var_kind == VariableKind.INDEXED: self.var_kinds[var_name] = ('i_result', n_i_vars) n_i_vars += 1 - elif kind == VariableKind.UNINDEXED: + elif var_kind == VariableKind.UNINDEXED: self.var_kinds[var_name] = ('u_result', n_u_vars) n_u_vars += 1 - elif kind == VariableKind.EXTENDED_INDEXED: + elif var_kind == VariableKind.EXTENDED_INDEXED: self.var_kinds[var_name] = ('i_prime_result', n_i_prime_vars) n_i_prime_vars += 1 diff --git a/topology.py b/topology.py index cf6408e0b5cb882a0d668875892dbd5df3bc32de..550ce082357e5f29cab92720416777dd0e868f4a 100644 --- a/topology.py +++ b/topology.py @@ -24,7 +24,11 @@ THE SOFTWARE. from Model_Library.component.core import ComponentCommodity, ComponentKind from Model_Library.dynamics import AggregatedDynamic, TreeDynamic, TrivialDynamic -from Model_Library.optimization_model import OptimizationBlock, OptimizationModel +from Model_Library.optimization_model import ( + OptimizationBlock, + OptimizationModel, + VariableKind, +) from enum import Enum import importlib @@ -507,7 +511,7 @@ class Topology: ) for flow in self._flows: - base_variable_names.append(flow) + base_variable_names.append((flow, VariableKind.INDEXED)) result = block.extract_result(base_variable_names) @@ -527,7 +531,7 @@ class Topology: ) for flow in self._flows: - operational_base_variable_names.append(flow) + operational_base_variable_names.append((flow, VariableKind.INDEXED)) for period_index in range(len(block.dynamic.period_dynamics)): period_block = block.blocks[str(period_index)]