From 24a6ed1c17df57946feb5f593df531a089b1cae0 Mon Sep 17 00:00:00 2001 From: "christoph.von.oy" <christoph.von.oy@rwth-aachen.de> Date: Thu, 2 May 2024 16:00:42 +0200 Subject: [PATCH] Moved VariableKind into base variable names Is necessary for constructing an EntityResult withoud a constructed OptimizationModel --- component/adapter.py | 11 +++++++++-- component/core.py | 27 +++++++++++++++++++-------- component/electricity.py | 3 ++- component/heat.py | 3 ++- optimization_model.py | 28 ++++++---------------------- topology.py | 10 +++++++--- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/component/adapter.py b/component/adapter.py index 2446819..b629746 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 a67777a..7fc3987 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 c738895..15202c8 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 ea51bd1..b841a5c 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 ecdc6e9..31f2db6 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 cf6408e..550ce08 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)] -- GitLab