flixopt 2.1.1__py3-none-any.whl → 2.2.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flixopt might be problematic. Click here for more details.
- docs/release-notes/v2.2.0.md +55 -0
- docs/user-guide/Mathematical Notation/Investment.md +115 -0
- flixopt/calculation.py +65 -37
- flixopt/components.py +115 -73
- flixopt/core.py +966 -451
- flixopt/effects.py +269 -65
- flixopt/elements.py +79 -49
- flixopt/features.py +134 -85
- flixopt/flow_system.py +99 -16
- flixopt/interface.py +142 -51
- flixopt/io.py +56 -27
- flixopt/linear_converters.py +3 -3
- flixopt/plotting.py +34 -16
- flixopt/results.py +806 -108
- flixopt/structure.py +64 -10
- flixopt/utils.py +6 -9
- {flixopt-2.1.1.dist-info → flixopt-2.2.0b0.dist-info}/METADATA +1 -1
- {flixopt-2.1.1.dist-info → flixopt-2.2.0b0.dist-info}/RECORD +21 -21
- {flixopt-2.1.1.dist-info → flixopt-2.2.0b0.dist-info}/WHEEL +1 -1
- {flixopt-2.1.1.dist-info → flixopt-2.2.0b0.dist-info}/top_level.txt +0 -1
- docs/release-notes/v2.1.1.md +0 -11
- site/release-notes/_template.txt +0 -32
- {flixopt-2.1.1.dist-info → flixopt-2.2.0b0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Release v2.2.0
|
|
2
|
+
|
|
3
|
+
**Release Date:** YYYY-MM-DD
|
|
4
|
+
|
|
5
|
+
## What's New
|
|
6
|
+
|
|
7
|
+
### Scenarios
|
|
8
|
+
Scenarios are a new feature of flixopt. They can be used to model uncertainties in the flow system, such as:
|
|
9
|
+
* Different demand profiles
|
|
10
|
+
* Different price forecasts
|
|
11
|
+
* Different weather conditions
|
|
12
|
+
* Different climate conditions
|
|
13
|
+
The might also be used to model an evolving system with multiple investment periods. Each **scenario** might be a new year, a new month, or a new day, with a different set of investment decisions to take.
|
|
14
|
+
|
|
15
|
+
The weighted sum of the total objective effect of each scenario is used as the objective of the optimization.
|
|
16
|
+
|
|
17
|
+
#### Investments and scenarios
|
|
18
|
+
Scenarios allow for more flexibility in investment decisions.
|
|
19
|
+
You can decide to allow different investment decisions for each scenario, or to allow a single investment decision for a subset of all scnarios, while not allowing for an invest in others.
|
|
20
|
+
This enables the following use cases:
|
|
21
|
+
* Find the best investment decision for each scenario individually
|
|
22
|
+
* Find the best overall investment decision for possible scenarios (robust decision-making)
|
|
23
|
+
* Find the best overall investment decision for a subset of all scenarios
|
|
24
|
+
|
|
25
|
+
The last one might be useful if you want to model a system with multiple investment periods, where one investment decision is made for more than one scenario.
|
|
26
|
+
This might occur when scenarios represent years or months, while an investment decision influences the system for multiple years or months.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Other new features
|
|
30
|
+
* Balanced storage - Storage charging and discharging sizes can now be forced to be equal in when optimizing their size.
|
|
31
|
+
* Feature 2 - Description
|
|
32
|
+
|
|
33
|
+
## Improvements
|
|
34
|
+
|
|
35
|
+
* Improvement 1 - Description
|
|
36
|
+
* Improvement 2 - Description
|
|
37
|
+
|
|
38
|
+
## Bug Fixes
|
|
39
|
+
|
|
40
|
+
* Fixed issue with X
|
|
41
|
+
* Resolved problem with Y
|
|
42
|
+
|
|
43
|
+
## Breaking Changes
|
|
44
|
+
|
|
45
|
+
* Change 1 - Migration instructions
|
|
46
|
+
* Change 2 - Migration instructions
|
|
47
|
+
|
|
48
|
+
## Deprecations
|
|
49
|
+
|
|
50
|
+
* Feature X will be removed in v{next_version}
|
|
51
|
+
|
|
52
|
+
## Dependencies
|
|
53
|
+
|
|
54
|
+
* Added dependency X v1.2.3
|
|
55
|
+
* Updated dependency Y to v2.0.0
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Investments
|
|
2
|
+
|
|
3
|
+
## Current state
|
|
4
|
+
$$
|
|
5
|
+
\beta_{\text{invest}} \cdot \text{max}(\epsilon, \text V^{\text L}) \leq V \leq \beta_{\text{invest}} \cdot \text V^{\text U}
|
|
6
|
+
$$
|
|
7
|
+
With:
|
|
8
|
+
- $V$ = size
|
|
9
|
+
- $V^{\text L}$ = minimum size
|
|
10
|
+
- $V^{\text U}$ = maximum size
|
|
11
|
+
- $\epsilon$ = epsilon, a small number (such as $1e^{-5}$)
|
|
12
|
+
- $\beta_{invest} \in {0,1}$ = wether the size is invested or not
|
|
13
|
+
|
|
14
|
+
_Please edit the use cases as needed_
|
|
15
|
+
## Quickfix 1: Optimize the single best size overall
|
|
16
|
+
### Single variable
|
|
17
|
+
This is already possible and should be, as this is a needed use case
|
|
18
|
+
An additional factor to when the size is actually available might me practical (Which indicates the (fixed) time of investment)
|
|
19
|
+
## Math
|
|
20
|
+
$$
|
|
21
|
+
V(p) = V * a(p)
|
|
22
|
+
$$
|
|
23
|
+
with:
|
|
24
|
+
- $V$ = size
|
|
25
|
+
- $a(p)$ = factor for availlability per period
|
|
26
|
+
|
|
27
|
+
Factor $a(p)$ is simply multiplied with relative minimum or maximum(t). This is already possible by doing this yourself.
|
|
28
|
+
Effectively, the relative minimum or maximum are altered before using the same constraiints as before.
|
|
29
|
+
THis might lead to some issues regariding minimum_load factor, or others, as the size is not 0 in a scenario where the component cant produce.
|
|
30
|
+
**Therefore this might not be the best choice. See (#Variable per Scenario)
|
|
31
|
+
|
|
32
|
+
## Variable per Scenario
|
|
33
|
+
- **size** and **invest** as a variable per period $V(s)$ and $\beta_{invest}(s)$
|
|
34
|
+
- with scenario $s \in S$
|
|
35
|
+
|
|
36
|
+
### Usecase 1: Optimize the size for each Scenario independently
|
|
37
|
+
Restrictions are seperatly for each scenario
|
|
38
|
+
No changes needed. This could be the default behaviour.
|
|
39
|
+
|
|
40
|
+
### Usecase 2: Optimize ONE size for ALL scenarios
|
|
41
|
+
The size is the same globally, but not a scalar, but a variable per scenario $V(s)$
|
|
42
|
+
#### 2a: The same size in all scenarios
|
|
43
|
+
$$
|
|
44
|
+
V(s) = V(s') \quad \forall s,s' \in S
|
|
45
|
+
$$
|
|
46
|
+
|
|
47
|
+
With:
|
|
48
|
+
- $V(s)$ and $V(s')$ = size
|
|
49
|
+
- $S$ = set of scenarios
|
|
50
|
+
|
|
51
|
+
#### 2b: The same size, but can be 0 prior to the first increment
|
|
52
|
+
- Find the Optimal time of investment.
|
|
53
|
+
- Force an investment in a certain scenario (parameter optional as a list/array ob booleans)
|
|
54
|
+
- Combine optional and minimum/maximum size to force an investment inside a range if scenarios
|
|
55
|
+
|
|
56
|
+
$$
|
|
57
|
+
\beta_{\text{invest}}(s) \leq \beta_{\text{invest}}(s+1) \quad \forall s \in \{1,2,\ldots,S-1\}
|
|
58
|
+
$$
|
|
59
|
+
|
|
60
|
+
$$
|
|
61
|
+
V(s') - V(s) \leq M \cdot (2 - \beta_{\text{invest}}(s) - \beta_{\text{invest}}(s')) \quad \forall s, s' \in S
|
|
62
|
+
$$
|
|
63
|
+
$$
|
|
64
|
+
V(s') - V(s) \geq M \cdot (2 - \beta_{\text{invest}}(s) - \beta_{\text{invest}}(s')) \quad \forall s, s' \in S
|
|
65
|
+
$$
|
|
66
|
+
|
|
67
|
+
This could be the default behaviour. (which would be consistent with other variables)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Switch
|
|
71
|
+
|
|
72
|
+
$$
|
|
73
|
+
\begin{aligned}
|
|
74
|
+
& \text{SWITCH}_s \in \{0,1\} \quad \forall s \in \{1,2,\ldots,S\} \\
|
|
75
|
+
& \sum_{s=1}^{S} \text{SWITCH}_s = 1 \\
|
|
76
|
+
& \beta_{\text{invest}}(s) = \sum_{s'=1}^{s} \text{SWITCH}_{s'} \quad \forall s \in \{1,2,\ldots,S\} \\
|
|
77
|
+
\end{aligned}
|
|
78
|
+
$$
|
|
79
|
+
|
|
80
|
+
$$
|
|
81
|
+
\begin{aligned}
|
|
82
|
+
& V(s) \leq V_{\text{actual}} \quad \forall s \in \{1,2,\ldots,S\} \\
|
|
83
|
+
& V(s) \geq V_{\text{actual}} - M \cdot (1 - \beta_{\text{invest}}(s)) \quad \forall s \in \{1,2,\ldots,S\}
|
|
84
|
+
\end{aligned}
|
|
85
|
+
$$
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
### Usecase 3: Find the best scenario to increment the size (Timing of the investment)
|
|
91
|
+
The size can only increment once (based on a starting point). This allows to optimize the timing of an investment.
|
|
92
|
+
#### Math
|
|
93
|
+
Treat $\beta_{invest}$ like an ON/OFF variable, and introduce a SwitchOn, that can only be active once.
|
|
94
|
+
|
|
95
|
+
*Thoughts:*
|
|
96
|
+
- Treating $\beta_{invest}$ like an ON/OFF variable suggest using the already presentconstraints linked to On/OffModel
|
|
97
|
+
- The timing could be constraint to be first in scenario x, or last in scenario y
|
|
98
|
+
- Restrict the number of consecutive scenarios
|
|
99
|
+
THis might needs the OnOffModel to be more generic (HOURS). Further, the span between scenarios needs to be weighted (like dt_in_hours), or the scenarios need to be measureable (integers)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Others
|
|
103
|
+
|
|
104
|
+
#### Usecase 4: Only increase/decrease the size
|
|
105
|
+
Start from a certain size. For each scenario, the size can increase, but never decrease. (Or the other way around).
|
|
106
|
+
This would mean that a size expansion is possible,
|
|
107
|
+
|
|
108
|
+
#### Usecase 5: Restrict the increment in size per scenario
|
|
109
|
+
Restrict how much the size can increase/decrease for in scenario, based on the prior scenario.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
Many more are possible
|
flixopt/calculation.py
CHANGED
|
@@ -12,6 +12,7 @@ import logging
|
|
|
12
12
|
import math
|
|
13
13
|
import pathlib
|
|
14
14
|
import timeit
|
|
15
|
+
import warnings
|
|
15
16
|
from typing import Any, Dict, List, Optional, Union
|
|
16
17
|
|
|
17
18
|
import numpy as np
|
|
@@ -43,20 +44,32 @@ class Calculation:
|
|
|
43
44
|
self,
|
|
44
45
|
name: str,
|
|
45
46
|
flow_system: FlowSystem,
|
|
46
|
-
|
|
47
|
+
selected_timesteps: Optional[pd.DatetimeIndex] = None,
|
|
48
|
+
selected_scenarios: Optional[pd.Index] = None,
|
|
47
49
|
folder: Optional[pathlib.Path] = None,
|
|
50
|
+
active_timesteps: Optional[pd.DatetimeIndex] = None,
|
|
48
51
|
):
|
|
49
52
|
"""
|
|
50
53
|
Args:
|
|
51
54
|
name: name of calculation
|
|
52
55
|
flow_system: flow_system which should be calculated
|
|
53
|
-
|
|
56
|
+
selected_timesteps: timesteps which should be used for calculation. If None, then all timesteps are used.
|
|
57
|
+
selected_scenarios: scenarios which should be used for calculation. If None, then all scenarios are used.
|
|
54
58
|
folder: folder where results should be saved. If None, then the current working directory is used.
|
|
59
|
+
active_timesteps: Deprecated. Use selected_timesteps instead.
|
|
55
60
|
"""
|
|
61
|
+
if active_timesteps is not None:
|
|
62
|
+
warnings.warn(
|
|
63
|
+
'active_timesteps is deprecated. Use selected_timesteps instead.',
|
|
64
|
+
DeprecationWarning,
|
|
65
|
+
stacklevel=2,
|
|
66
|
+
)
|
|
67
|
+
selected_timesteps = active_timesteps
|
|
56
68
|
self.name = name
|
|
57
69
|
self.flow_system = flow_system
|
|
58
70
|
self.model: Optional[SystemModel] = None
|
|
59
|
-
self.
|
|
71
|
+
self.selected_timesteps = selected_timesteps
|
|
72
|
+
self.selected_scenarios = selected_scenarios
|
|
60
73
|
|
|
61
74
|
self.durations = {'modeling': 0.0, 'solving': 0.0, 'saving': 0.0}
|
|
62
75
|
self.folder = pathlib.Path.cwd() / 'results' if folder is None else pathlib.Path(folder)
|
|
@@ -74,47 +87,49 @@ class Calculation:
|
|
|
74
87
|
def main_results(self) -> Dict[str, Union[Scalar, Dict]]:
|
|
75
88
|
from flixopt.features import InvestmentModel
|
|
76
89
|
|
|
77
|
-
|
|
90
|
+
main_results = {
|
|
78
91
|
'Objective': self.model.objective.value,
|
|
79
|
-
'Penalty':
|
|
92
|
+
'Penalty': self.model.effects.penalty.total.solution.values,
|
|
80
93
|
'Effects': {
|
|
81
94
|
f'{effect.label} [{effect.unit}]': {
|
|
82
|
-
'operation':
|
|
83
|
-
'invest':
|
|
84
|
-
'total':
|
|
95
|
+
'operation': effect.model.operation.total.solution.values,
|
|
96
|
+
'invest': effect.model.invest.total.solution.values,
|
|
97
|
+
'total': effect.model.total.solution.values,
|
|
85
98
|
}
|
|
86
99
|
for effect in self.flow_system.effects
|
|
87
100
|
},
|
|
88
101
|
'Invest-Decisions': {
|
|
89
102
|
'Invested': {
|
|
90
|
-
model.label_of_element:
|
|
103
|
+
model.label_of_element: model.size.solution
|
|
91
104
|
for component in self.flow_system.components.values()
|
|
92
105
|
for model in component.model.all_sub_models
|
|
93
|
-
if isinstance(model, InvestmentModel) and
|
|
106
|
+
if isinstance(model, InvestmentModel) and model.size.solution.max() >= CONFIG.modeling.EPSILON
|
|
94
107
|
},
|
|
95
108
|
'Not invested': {
|
|
96
|
-
model.label_of_element:
|
|
109
|
+
model.label_of_element: model.size.solution
|
|
97
110
|
for component in self.flow_system.components.values()
|
|
98
111
|
for model in component.model.all_sub_models
|
|
99
|
-
if isinstance(model, InvestmentModel) and
|
|
112
|
+
if isinstance(model, InvestmentModel) and model.size.solution.max() < CONFIG.modeling.EPSILON
|
|
100
113
|
},
|
|
101
114
|
},
|
|
102
115
|
'Buses with excess': [
|
|
103
116
|
{
|
|
104
117
|
bus.label_full: {
|
|
105
|
-
'input':
|
|
106
|
-
'output':
|
|
118
|
+
'input': bus.model.excess_input.solution.sum('time'),
|
|
119
|
+
'output': bus.model.excess_output.solution.sum('time'),
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
for bus in self.flow_system.buses.values()
|
|
110
123
|
if bus.with_excess
|
|
111
124
|
and (
|
|
112
|
-
|
|
113
|
-
or
|
|
125
|
+
bus.model.excess_input.solution.sum() > 1e-3
|
|
126
|
+
or bus.model.excess_output.solution.sum() > 1e-3
|
|
114
127
|
)
|
|
115
128
|
],
|
|
116
129
|
}
|
|
117
130
|
|
|
131
|
+
return utils.round_floats(main_results)
|
|
132
|
+
|
|
118
133
|
@property
|
|
119
134
|
def summary(self):
|
|
120
135
|
return {
|
|
@@ -128,6 +143,15 @@ class Calculation:
|
|
|
128
143
|
'Config': CONFIG.to_dict(),
|
|
129
144
|
}
|
|
130
145
|
|
|
146
|
+
@property
|
|
147
|
+
def active_timesteps(self) -> pd.DatetimeIndex:
|
|
148
|
+
warnings.warn(
|
|
149
|
+
'active_timesteps is deprecated. Use selected_timesteps instead.',
|
|
150
|
+
DeprecationWarning,
|
|
151
|
+
stacklevel=2,
|
|
152
|
+
)
|
|
153
|
+
return self.selected_timesteps
|
|
154
|
+
|
|
131
155
|
|
|
132
156
|
class FullCalculation(Calculation):
|
|
133
157
|
"""
|
|
@@ -183,8 +207,8 @@ class FullCalculation(Calculation):
|
|
|
183
207
|
|
|
184
208
|
def _activate_time_series(self):
|
|
185
209
|
self.flow_system.transform_data()
|
|
186
|
-
self.flow_system.time_series_collection.
|
|
187
|
-
|
|
210
|
+
self.flow_system.time_series_collection.set_selection(
|
|
211
|
+
timesteps=self.selected_timesteps, scenarios=self.selected_scenarios
|
|
188
212
|
)
|
|
189
213
|
|
|
190
214
|
|
|
@@ -199,7 +223,7 @@ class AggregatedCalculation(FullCalculation):
|
|
|
199
223
|
flow_system: FlowSystem,
|
|
200
224
|
aggregation_parameters: AggregationParameters,
|
|
201
225
|
components_to_clusterize: Optional[List[Component]] = None,
|
|
202
|
-
|
|
226
|
+
selected_timesteps: Optional[pd.DatetimeIndex] = None,
|
|
203
227
|
folder: Optional[pathlib.Path] = None,
|
|
204
228
|
):
|
|
205
229
|
"""
|
|
@@ -213,11 +237,13 @@ class AggregatedCalculation(FullCalculation):
|
|
|
213
237
|
components_to_clusterize: List of Components to perform aggregation on. If None, then all components are aggregated.
|
|
214
238
|
This means, teh variables in the components are equalized to each other, according to the typical periods
|
|
215
239
|
computed in the DataAggregation
|
|
216
|
-
|
|
240
|
+
selected_timesteps: pd.DatetimeIndex or None
|
|
217
241
|
list with indices, which should be used for calculation. If None, then all timesteps are used.
|
|
218
242
|
folder: folder where results should be saved. If None, then the current working directory is used.
|
|
219
243
|
"""
|
|
220
|
-
|
|
244
|
+
if flow_system.time_series_collection.scenarios is not None:
|
|
245
|
+
raise ValueError('Aggregation is not supported for scenarios yet. Please use FullCalculation instead.')
|
|
246
|
+
super().__init__(name, flow_system, selected_timesteps, folder=folder)
|
|
221
247
|
self.aggregation_parameters = aggregation_parameters
|
|
222
248
|
self.components_to_clusterize = components_to_clusterize
|
|
223
249
|
self.aggregation = None
|
|
@@ -272,9 +298,9 @@ class AggregatedCalculation(FullCalculation):
|
|
|
272
298
|
|
|
273
299
|
# Aggregation - creation of aggregated timeseries:
|
|
274
300
|
self.aggregation = Aggregation(
|
|
275
|
-
original_data=self.flow_system.time_series_collection.
|
|
276
|
-
|
|
277
|
-
)
|
|
301
|
+
original_data=self.flow_system.time_series_collection.as_dataset(
|
|
302
|
+
with_extra_timestep=False, with_constants=False
|
|
303
|
+
).to_dataframe(),
|
|
278
304
|
hours_per_time_step=float(dt_min),
|
|
279
305
|
hours_per_period=self.aggregation_parameters.hours_per_period,
|
|
280
306
|
nr_of_periods=self.aggregation_parameters.nr_of_periods,
|
|
@@ -286,9 +312,11 @@ class AggregatedCalculation(FullCalculation):
|
|
|
286
312
|
self.aggregation.cluster()
|
|
287
313
|
self.aggregation.plot(show=True, save=self.folder / 'aggregation.html')
|
|
288
314
|
if self.aggregation_parameters.aggregate_data_and_fix_non_binary_vars:
|
|
289
|
-
self.
|
|
290
|
-
self.aggregation.aggregated_data
|
|
291
|
-
|
|
315
|
+
for col in self.aggregation.aggregated_data.columns:
|
|
316
|
+
data = self.aggregation.aggregated_data[col].values
|
|
317
|
+
if col in self.flow_system.time_series_collection._has_extra_timestep:
|
|
318
|
+
data = np.append(data, data[-1])
|
|
319
|
+
self.flow_system.time_series_collection.update_time_series(col, data)
|
|
292
320
|
self.durations['aggregation'] = round(timeit.default_timer() - t_start_agg, 2)
|
|
293
321
|
|
|
294
322
|
|
|
@@ -327,13 +355,13 @@ class SegmentedCalculation(Calculation):
|
|
|
327
355
|
self.nr_of_previous_values = nr_of_previous_values
|
|
328
356
|
self.sub_calculations: List[FullCalculation] = []
|
|
329
357
|
|
|
330
|
-
self.all_timesteps = self.flow_system.time_series_collection.
|
|
331
|
-
self.all_timesteps_extra = self.flow_system.time_series_collection.
|
|
358
|
+
self.all_timesteps = self.flow_system.time_series_collection._full_timesteps
|
|
359
|
+
self.all_timesteps_extra = self.flow_system.time_series_collection._full_timesteps_extra
|
|
332
360
|
|
|
333
361
|
self.segment_names = [
|
|
334
362
|
f'Segment_{i + 1}' for i in range(math.ceil(len(self.all_timesteps) / self.timesteps_per_segment))
|
|
335
363
|
]
|
|
336
|
-
self.
|
|
364
|
+
self.selected_timesteps_per_segment = self._calculate_timesteps_of_segment()
|
|
337
365
|
|
|
338
366
|
assert timesteps_per_segment > 2, 'The Segment length must be greater 2, due to unwanted internal side effects'
|
|
339
367
|
assert self.timesteps_per_segment_with_overlap <= len(self.all_timesteps), (
|
|
@@ -359,7 +387,7 @@ class SegmentedCalculation(Calculation):
|
|
|
359
387
|
logger.info(f'{" Segmented Solving ":#^80}')
|
|
360
388
|
|
|
361
389
|
for i, (segment_name, timesteps_of_segment) in enumerate(
|
|
362
|
-
zip(self.segment_names, self.
|
|
390
|
+
zip(self.segment_names, self.selected_timesteps_per_segment, strict=False)
|
|
363
391
|
):
|
|
364
392
|
if self.sub_calculations:
|
|
365
393
|
self._transfer_start_values(i)
|
|
@@ -370,7 +398,7 @@ class SegmentedCalculation(Calculation):
|
|
|
370
398
|
)
|
|
371
399
|
|
|
372
400
|
calculation = FullCalculation(
|
|
373
|
-
f'{self.name}-{segment_name}', self.flow_system,
|
|
401
|
+
f'{self.name}-{segment_name}', self.flow_system, selected_timesteps=timesteps_of_segment
|
|
374
402
|
)
|
|
375
403
|
self.sub_calculations.append(calculation)
|
|
376
404
|
calculation.do_modeling()
|
|
@@ -404,9 +432,9 @@ class SegmentedCalculation(Calculation):
|
|
|
404
432
|
This function gets the last values of the previous solved segment and
|
|
405
433
|
inserts them as start values for the next segment
|
|
406
434
|
"""
|
|
407
|
-
timesteps_of_prior_segment = self.
|
|
435
|
+
timesteps_of_prior_segment = self.selected_timesteps_per_segment[segment_index - 1]
|
|
408
436
|
|
|
409
|
-
start = self.
|
|
437
|
+
start = self.selected_timesteps_per_segment[segment_index][0]
|
|
410
438
|
start_previous_values = timesteps_of_prior_segment[self.timesteps_per_segment - self.nr_of_previous_values]
|
|
411
439
|
end_previous_values = timesteps_of_prior_segment[self.timesteps_per_segment - 1]
|
|
412
440
|
|
|
@@ -435,12 +463,12 @@ class SegmentedCalculation(Calculation):
|
|
|
435
463
|
comp.initial_charge_state = self._original_start_values[comp.label_full]
|
|
436
464
|
|
|
437
465
|
def _calculate_timesteps_of_segment(self) -> List[pd.DatetimeIndex]:
|
|
438
|
-
|
|
466
|
+
selected_timesteps_per_segment = []
|
|
439
467
|
for i, _ in enumerate(self.segment_names):
|
|
440
468
|
start = self.timesteps_per_segment * i
|
|
441
469
|
end = min(start + self.timesteps_per_segment_with_overlap, len(self.all_timesteps))
|
|
442
|
-
|
|
443
|
-
return
|
|
470
|
+
selected_timesteps_per_segment.append(self.all_timesteps[start:end])
|
|
471
|
+
return selected_timesteps_per_segment
|
|
444
472
|
|
|
445
473
|
@property
|
|
446
474
|
def timesteps_per_segment_with_overlap(self):
|