From 7f0021b55d5f0f2ec60d618e88f0bafea86c1684 Mon Sep 17 00:00:00 2001 From: "christoph.von.oy" <christoph.von.oy@rwth-aachen.de> Date: Tue, 21 May 2024 22:26:40 +0200 Subject: [PATCH] Refactored results extraction and storage --- dynamics.py | 4 +- optimization_model.py | 174 ++++++++++++++++++++++++++++++------------ topology.py | 29 +++---- 3 files changed, 143 insertions(+), 64 deletions(-) diff --git a/dynamics.py b/dynamics.py index 11c8416..50d441f 100644 --- a/dynamics.py +++ b/dynamics.py @@ -1501,7 +1501,9 @@ def resample_first_state_into( raise ValueError( f"The period dynamic and the aggregated dynamic have to be part of the same period aggregation!" ) - target_values[:, dynamic.period_index] = values + target_values[:, dynamic.period_index] = values[ + :, 0 + ] # TODO: the first dimension of values and target_values is 0, somehow values[:,0] is necessary, and values on its own does not work def resample_variable(variable, dynamic: Dynamic, target_dynamic: Dynamic): diff --git a/optimization_model.py b/optimization_model.py index 9108e29..dbf54a2 100644 --- a/optimization_model.py +++ b/optimization_model.py @@ -133,23 +133,25 @@ class OptimizationModel(OptimizationBlock): == TerminationCondition.optimal ) -class EntityResult: - def __init__(self, var_names, architecture, dynamic): + +class DynamicResult: + def __init__(self, dynamic, var_names): n_u_vars = 0 n_i_vars = 0 n_i_prime_vars = 0 - self.var_kinds = dict() + self.var_map = dict() + for var_name, var_kind in var_names: if var_kind == VariableKind.INDEXED: - self.var_kinds[var_name] = ('i_result', n_i_vars) + self.var_map[var_name] = (1, n_i_vars) n_i_vars += 1 elif var_kind == VariableKind.UNINDEXED: - self.var_kinds[var_name] = ('u_result', n_u_vars) + self.var_map[var_name] = (0, n_u_vars) n_u_vars += 1 elif var_kind == VariableKind.EXTENDED_INDEXED: - self.var_kinds[var_name] = ('i_prime_result', n_i_prime_vars) + self.var_map[var_name] = (2, n_i_prime_vars) n_i_prime_vars += 1 - + self.n_u_vars = n_u_vars self.u_result = np.empty(n_u_vars, dtype=float) @@ -157,67 +159,141 @@ class EntityResult: self.i_result = np.empty((n_i_vars, dynamic.shape()), dtype=float) self.n_i_prime_vars = n_i_prime_vars - self.i_prime_first_result = np.empty((n_i_prime_vars, dynamic.first_state_shape()), dtype=float) + self.i_prime_first_result = np.empty( + (n_i_prime_vars, dynamic.first_state_shape()), dtype=float + ) self.i_prime_result = np.empty((n_i_prime_vars, dynamic.shape()), dtype=float) - self.architecture = architecture self.dynamic = dynamic - self.sub_results = dict() - def extract_result(self, block): # TODO: when the resampling is simple copying, then detect that here and extract in the loop over self.var_kinds the values directly into the EntityResult instead of creating new ndarrays u_values = np.empty(self.n_u_vars, dtype=float) i_values = np.empty((self.n_i_vars, block.dynamic.shape()), dtype=float) - i_prime_first_values = np.empty((self.n_i_prime_vars, block.dynamic.first_state_shape()), dtype=float) - i_prime_values = np.empty((self.n_i_prime_vars, block.dynamic.shape()), dtype=float) - for var_name, (var_kind, index) in self.var_kinds.items(): - if var_kind == 'i_result': + i_prime_first_values = np.empty( + (self.n_i_prime_vars, block.dynamic.first_state_shape()), dtype=float + ) + i_prime_values = np.empty( + (self.n_i_prime_vars, block.dynamic.shape()), dtype=float + ) + + for var_name, (outer_index, inner_index) in self.var_map.items(): + if outer_index == 1: value_object = block.component_dict[var_name].get_values() - i_values[index] = np.fromiter((value_object[t] for t in block.T), float) - elif var_kind == 'u_result': - u_values[index] = pyo.value(block.component_dict[var_name]) - elif var_kind == 'i_prime_result': + i_values[inner_index] = np.fromiter( + (value_object[t] for t in block.T), float + ) + elif outer_index == 0: + u_values[inner_index] = pyo.value(block.component_dict[var_name]) + elif outer_index == 2: value_object = block.component_dict[var_name].get_values() - i_prime_first_values[index] = value_object[block.T_prime.first()] - i_prime_values[index] = np.fromiter((value_object[t] for t in block.T), float) + i_prime_first_values[inner_index] = value_object[block.T_prime.first()] + i_prime_values[inner_index] = np.fromiter( + (value_object[t] for t in block.T), float + ) self.u_result = u_values resample_into(i_values, block.dynamic, self.i_result, self.dynamic) - resample_first_state_into(i_prime_first_values, block.dynamic, self.i_prime_first_result, self.dynamic) + resample_first_state_into( + i_prime_first_values, block.dynamic, self.i_prime_first_result, self.dynamic + ) resample_into(i_prime_values, block.dynamic, self.i_prime_result, self.dynamic) - def add_sub_result(self, key, result): - self.sub_results[key] = result - def __getitem__(self, var_name): - if var_name in self.var_kinds: - res_name, index = self.var_kinds[var_name] - if res_name == 'i_result': - return Profile(self.i_result[index], self.dynamic) - elif res_name == 'u_result': - return self.u_result[index] - elif res_name == 'i_prime_result': - return Profile(self.i_prime_result[index], self.dynamic) + if var_name in self.var_map: + outer_index, inner_index = self.var_map[var_name] + if outer_index == 1: + return Profile(self.i_result[inner_index], self.dynamic) + elif outer_index == 0: + return self.u_result[inner_index] + elif outer_index == 2: + return Profile(self.i_prime_result[inner_index], self.dynamic) else: return None + + def to_excel(self, excel_writer, **kwargs): + sheet_name = kwargs.get("sheet_name", "") + + kwargs["sheet_name"] = "u" if sheet_name == "" else sheet_name + "_u" + df = pd.Series( + self.u_result, + index=( + var_name + for var_name, (outer_index, _) in self.var_map.items() + if outer_index == 0 + ), + ) + df.to_excel(excel_writer, **kwargs) + + kwargs["sheet_name"] = "i" if sheet_name == "" else sheet_name + "_i" + df = pd.DataFrame( + np.transpose(self.i_result), + index=self.dynamic.pandas_index(), + columns=( + var_name + for var_name, (outer_index, _) in self.var_map.items() + if outer_index == 1 + ), + ) + df.to_excel(excel_writer, **kwargs) + + kwargs["sheet_name"] = ( + "i_prime" if sheet_name == "" else sheet_name + "_i_prime" + ) + df_first = pd.DataFrame( + np.transpose(self.i_prime_first_result), + index=self.dynamic.first_state_pandas_index(), + columns=( + var_name + for var_name, (outer_index, _) in self.var_map.items() + if outer_index == 2 + ), + ) + df = pd.DataFrame( + np.transpose(self.i_prime_result), + index=self.dynamic.pandas_index(), + columns=( + var_name + for var_name, (outer_index, _) in self.var_map.items() + if outer_index == 2 + ), + ) + df = pd.concat([df, df_first]) + df.sort_index(inplace=True) + df.to_excel(excel_writer, **kwargs) + + +class EntityResult: + def __init__(self, architecture): + self.architecture = architecture + self.registred_dynamics = [] + self.names = [] + self.var_map = dict() + + def register_dynamic(self, dynamic, name, var_names): + self.registred_dynamics.append((dynamic, var_names)) + self.names.append(name) + for var_name, _ in var_names: + self.var_map[var_name] = dynamic + + def compile(self): + self.data = dict() + + for dynamic, var_names in self.registred_dynamics: + self.data[dynamic] = DynamicResult(dynamic, var_names) + + def extract_result(self, block, dynamic): + self.data[dynamic].extract_result(block) + + def __getitem__(self, var_name): + if var_name in self.var_map: + return self.data[self.var_map[var_name]][var_name] else: return None def to_excel(self, excel_writer, **kwargs): - sheet_name = kwargs.get('sheet_name', '') - kwargs['sheet_name'] = 'unindexed' if sheet_name == '' else sheet_name + '_unindexed' - u_result = pd.Series(self.u_result, index=(var_name for var_name, (var_kind, _) in self.var_kinds.items() if var_kind == 'u_result')) - u_result.to_excel(excel_writer, **kwargs) - kwargs['sheet_name'] = 'T' if sheet_name == '' else sheet_name + '_T' - i_result = pd.DataFrame(np.transpose(self.i_result), index=self.dynamic.pandas_index(), columns=(var_name for var_name, (var_kind, _) in self.var_kinds.items() if var_kind == 'i_result')) - i_result.to_excel(excel_writer, **kwargs) - kwargs['sheet_name'] = 'T_prime' if sheet_name == '' else sheet_name + '_T_prime' - i_prime_first_result = pd.DataFrame(np.transpose(self.i_prime_first_result), index=self.dynamic.first_state_pandas_index(), columns=(var_name for var_name, (var_kind, _) in self.var_kinds.items() if var_kind == 'i_prime_result')) - i_prime_result = pd.DataFrame(np.transpose(self.i_prime_result), index=self.dynamic.pandas_index(), columns=(var_name for var_name, (var_kind, _) in self.var_kinds.items() if var_kind == 'i_prime_result')) - i_prime_result = pd.concat([i_prime_first_result, i_prime_result]) - i_prime_result.sort_index(inplace=True) - i_prime_result.to_excel(excel_writer, **kwargs) - for key, sub_result in self.sub_results.items(): - kwargs['sheet_name'] = str(key) if sheet_name == '' else sheet_name + '_' + str(key) - sub_result.to_excel(excel_writer, **kwargs) + sheet_name = kwargs.get("sheet_name", "") + + for (_, result), name in zip(self.data.items(), self.names): + kwargs["sheet_name"] = name if sheet_name == "" else sheet_name + "_" + name + result.to_excel(excel_writer, **kwargs) diff --git a/topology.py b/topology.py index e942c3c..3a1ecb5 100644 --- a/topology.py +++ b/topology.py @@ -511,9 +511,8 @@ class Topology: for flow in self._flows: base_variable_names.append((flow, VariableKind.INDEXED)) - result = EntityResult( - base_variable_names, architecture, architecture.dynamic - ) + result = EntityResult(architecture) + result.register_dynamic(architecture.dynamic, "", base_variable_names) elif isinstance(architecture, PeriodAggregation): design_base_variable_names = [] @@ -522,8 +521,9 @@ class Topology: self._components[component].design_base_variable_names() ) - result = EntityResult( - design_base_variable_names, architecture, architecture.dynamic + result = EntityResult(architecture) + result.register_dynamic( + architecture.dynamic, "", design_base_variable_names ) operational_base_variable_names = [] @@ -535,16 +535,17 @@ class Topology: for flow in self._flows: operational_base_variable_names.append((flow, VariableKind.INDEXED)) - for period_index, period_dynamic in enumerate(architecture.period_dynamics): - period_result = EntityResult( - operational_base_variable_names, None, period_dynamic - ) - - result.add_sub_result(period_index, period_result) + result.register_dynamic( + architecture.value_dynamic, + "aggregated", + operational_base_variable_names, + ) else: raise ValueError(f"Invalid architecture type {type(architecture)}") + result.compile() + self._results[key] = result self._last_result_key = key @@ -556,15 +557,15 @@ class Topology: result = self._results[key] if isinstance(result.architecture, TrivialArchitecture): - result.extract_result(block) + result.extract_result(block, result.architecture.dynamic) elif isinstance(result.architecture, PeriodAggregation): - result.extract_result(block) + result.extract_result(block, result.architecture.dynamic) for period_index in range(result.architecture.number_of_periods()): period_block = block.blocks[str(period_index)] - result.sub_results[period_index].extract_result(period_block) + result.extract_result(period_block, result.architecture.value_dynamic) else: raise ValueError(f"Invalid architecture type {type(result.architecture)}") -- GitLab