diff --git a/dynamics.py b/dynamics.py index 02d438ef47bb755d4d7ab31a6bb760cc203f4734..5e011f85f23a842e6cddabbc1cc73a2ef04315ff 100644 --- a/dynamics.py +++ b/dynamics.py @@ -1048,10 +1048,10 @@ class AggregatedDynamic(Dynamic): np.full(number_of_time_steps_per_period, step_length, dtype=int) ) root_dynamic = self.dynamic_tree.root() - self.shape_ = sum(len(period) for period in periods) - self.state_shape_ = sum(len(period) + 1 for period in periods) self.period_dynamics = [] self.n_p = [] + running_index = 0 + self.offsets_ = [] for i, period in enumerate(periods): index = 0 period_indices = [0] @@ -1066,8 +1066,12 @@ class AggregatedDynamic(Dynamic): self.n_p.append( sum(1 for period_index in period_order if period_index == i) ) + self.offsets_.append((running_index, running_index + len(period))) + running_index += len(period) self.period_order = period_order self.n = len(period_order) + self.shape_ = running_index + self.state_shape_ = running_index + len(periods) # sanity check 5: all elements in period order are valid period indices (above n_p[i] is the number of times that period index i appears in period order -> sum(n_p) == len(period_order)) if sum(n_p for n_p in self.n_p) != len(period_order): @@ -1075,6 +1079,12 @@ class AggregatedDynamic(Dynamic): "All elements in period order have to be valid period indices!" ) + def number_of_periods(self) -> int: + return len(self.period_dynamics) + + def offsets(self, period_index) -> Tuple[int]: + return self.offsets_[period_index] + def number_of_steps(self) -> int: return self.dynamic.number_of_steps() @@ -1129,7 +1139,7 @@ class PeriodDynamic(Dynamic): def resample( values, dynamic: Dynamic, target_dynamic: Dynamic -): # values: type hinting Union[np-array, dict[int, np-array]], type hinting Union[np-array, dict[int, np-array]] +): # values: type hinting a np-array, type hinting a np-array if dynamic == target_dynamic: return values elif isinstance(dynamic, TreeDynamic) and isinstance(target_dynamic, TreeDynamic): @@ -1168,7 +1178,8 @@ def resample_aggregation_down( raise ValueError( f"The period dynamic has to be part of the aggregated dynamic!" ) - return values[target_dynamic.period_index] + offset = dynamic.offsets(target_dynamic.period_index) + return values[offset[0] : offset[1]] def resample_variable(variable, dynamic: Dynamic, target_dynamic: Dynamic): @@ -1196,9 +1207,7 @@ def resample_variable_tree(variable, dynamic: TreeDynamic, target_dynamic: TreeD class Profile: - def __init__( - self, values, dynamic: Dynamic - ): # values: type hinting Union[np-array, dict[int, np-array]] + def __init__(self, values, dynamic: Dynamic): # values: type hinting np-array self.values = values self.dynamic = dynamic @@ -1217,18 +1226,20 @@ class Profile: } elif isinstance(dynamic, AggregatedDynamic): df = pd.read_csv(path, index_col=[0, 1]) - profiles = {column: dict() for column in df.columns} - for period_index in df.index.levels[0]: - if ( - len(df.loc[period_index]) - != dynamic.period_dynamics[period_index].number_of_steps() - ): - raise ValueError( - f"The number of rows in the csv file for a period and the number of steps in the period dynamic have to be the same!" - ) - for column in df.columns: - profiles[column][period_index] = df.loc[period_index][column].values - return {column: Profile(profiles[column], dynamic) for column in df.columns} + if len(df.index.levels[0]) != dynamic.number_of_periods(): + raise ValueError( + f"The number of periods in the csv file and the number of periods in the dynamic have the be the same!" + ) + if any( + len(df.loc[period_index]) != period_dynamic.number_of_steps() + for period_index, period_dynamic in enumerate(dynamic.period_dynamics) + ): + raise ValueError( + f"The number of rows in the csv file for a period and the number of segments in that period have the be the same!" + ) + return { + column: Profile(df[column].values, dynamic) for column in df.columns + } else: raise ValueError(f"Invalid dynamic type {type(dynamic)}!") diff --git a/optimization_model.py b/optimization_model.py index 2df8cd6c7fba81c3051863cc6773efe3eb91f1dd..316a2feaf6de221b8aebe6290fdcd40c5cd7e11e 100644 --- a/optimization_model.py +++ b/optimization_model.py @@ -152,9 +152,9 @@ class EntityResult: self.u_result = np.empty(n_u_vars, dtype=float) - self.i_result = np.empty((n_i_vars, dynamic.number_of_steps()), dtype=float) + self.i_result = np.empty((n_i_vars, dynamic.shape()), dtype=float) - self.i_prime_result = np.empty((n_i_prime_vars, dynamic.number_of_steps() + 1), dtype=float) + self.i_prime_result = np.empty((n_i_prime_vars, dynamic.state_shape()), dtype=float) self.dynamic = dynamic diff --git a/topology.py b/topology.py index 9fdd0eeda950344868b1f7dcb0998280e825f3c9..37d67c2cc8fc5aefbcacfe4fbdc0c7ffe0d79897 100644 --- a/topology.py +++ b/topology.py @@ -325,7 +325,7 @@ class Topology: for name in objectives: scaled_expression = 0.0 one_time_expression = 0.0 - for period_index in range(len(block.dynamic.period_dynamics)): + for period_index in range(block.dynamic.number_of_periods()): ( period_scaled_expression, period_one_time_expression, @@ -559,7 +559,7 @@ class Topology: elif isinstance(block.dynamic, (AggregatedDynamic)): self._results[key].extract_result(block) - for period_index in range(len(block.dynamic.period_dynamics)): + for period_index in range(block.dynamic.number_of_periods()): period_block = block.blocks[str(period_index)] self._results[key].sub_results[period_index].extract_result(