-
Notifications
You must be signed in to change notification settings - Fork 9
V3.0.0/main (#284) #319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V3.0.0/main (#284) #319
Changes from all commits
7467d2b
09949ea
334f183
579b894
c76fb29
cc3dbd4
b326abc
3b68281
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,115 @@ | ||||||||||
| # Investments | ||||||||||
|
|
||||||||||
| ## Current state | ||||||||||
| $$ | ||||||||||
| \beta_{\text{invest}} \cdot \text{max}(\epsilon, \text V^{\text L}) \leq V \leq \beta_{\text{invest}} \cdot \text V^{\text U} | ||||||||||
| $$ | ||||||||||
| With: | ||||||||||
| - $V$ = size | ||||||||||
| - $V^{\text L}$ = minimum size | ||||||||||
| - $V^{\text U}$ = maximum size | ||||||||||
| - $\epsilon$ = epsilon, a small number (such as $1e^{-5}$) | ||||||||||
| - $\beta_{invest} \in {0,1}$ = wether the size is invested or not | ||||||||||
|
|
||||||||||
| _Please edit the use cases as needed_ | ||||||||||
| ## Quickfix 1: Optimize the single best size overall | ||||||||||
| ### Single variable | ||||||||||
| This is already possible and should be, as this is a needed use case | ||||||||||
| An additional factor to when the size is actually available might me practical (Which indicates the (fixed) time of investment) | ||||||||||
| ## Math | ||||||||||
| $$ | ||||||||||
| V(p) = V * a(p) | ||||||||||
| $$ | ||||||||||
| with: | ||||||||||
| - $V$ = size | ||||||||||
| - $a(p)$ = factor for availlability per period | ||||||||||
|
|
||||||||||
| Factor $a(p)$ is simply multiplied with relative minimum or maximum(t). This is already possible by doing this yourself. | ||||||||||
| Effectively, the relative minimum or maximum are altered before using the same constraiints as before. | ||||||||||
| 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. | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix typo in "This" Line 29 contains a typo: "THis" should be "This". -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.
+This might lead to some issues regarding minimum_load factor, or others, as the size is not 0 in a scenario where the component cant produce.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| **Therefore this might not be the best choice. See (#Variable per Scenario) | ||||||||||
|
|
||||||||||
| ## Variable per Scenario | ||||||||||
| - **size** and **invest** as a variable per period $V(s)$ and $\beta_{invest}(s)$ | ||||||||||
| - with scenario $s \in S$ | ||||||||||
|
|
||||||||||
| ### Usecase 1: Optimize the size for each Scenario independently | ||||||||||
| Restrictions are seperatly for each scenario | ||||||||||
| No changes needed. This could be the default behaviour. | ||||||||||
|
|
||||||||||
| ### Usecase 2: Optimize ONE size for ALL scenarios | ||||||||||
| The size is the same globally, but not a scalar, but a variable per scenario $V(s)$ | ||||||||||
| #### 2a: The same size in all scenarios | ||||||||||
| $$ | ||||||||||
| V(s) = V(s') \quad \forall s,s' \in S | ||||||||||
| $$ | ||||||||||
|
|
||||||||||
| With: | ||||||||||
| - $V(s)$ and $V(s')$ = size | ||||||||||
| - $S$ = set of scenarios | ||||||||||
|
|
||||||||||
| #### 2b: The same size, but can be 0 prior to the first increment | ||||||||||
| - Find the Optimal time of investment. | ||||||||||
| - Force an investment in a certain scenario (parameter optional as a list/array ob booleans) | ||||||||||
| - Combine optional and minimum/maximum size to force an investment inside a range if scenarios | ||||||||||
|
|
||||||||||
| $$ | ||||||||||
| \beta_{\text{invest}}(s) \leq \beta_{\text{invest}}(s+1) \quad \forall s \in \{1,2,\ldots,S-1\} | ||||||||||
| $$ | ||||||||||
|
|
||||||||||
| $$ | ||||||||||
| V(s') - V(s) \leq M \cdot (2 - \beta_{\text{invest}}(s) - \beta_{\text{invest}}(s')) \quad \forall s, s' \in S | ||||||||||
| $$ | ||||||||||
| $$ | ||||||||||
| V(s') - V(s) \geq M \cdot (2 - \beta_{\text{invest}}(s) - \beta_{\text{invest}}(s')) \quad \forall s, s' \in S | ||||||||||
| $$ | ||||||||||
|
|
||||||||||
| This could be the default behaviour. (which would be consistent with other variables) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| ### Switch | ||||||||||
|
|
||||||||||
| $$ | ||||||||||
| \begin{aligned} | ||||||||||
| & \text{SWITCH}_s \in \{0,1\} \quad \forall s \in \{1,2,\ldots,S\} \\ | ||||||||||
| & \sum_{s=1}^{S} \text{SWITCH}_s = 1 \\ | ||||||||||
| & \beta_{\text{invest}}(s) = \sum_{s'=1}^{s} \text{SWITCH}_{s'} \quad \forall s \in \{1,2,\ldots,S\} \\ | ||||||||||
| \end{aligned} | ||||||||||
| $$ | ||||||||||
|
|
||||||||||
| $$ | ||||||||||
| \begin{aligned} | ||||||||||
| & V(s) \leq V_{\text{actual}} \quad \forall s \in \{1,2,\ldots,S\} \\ | ||||||||||
| & V(s) \geq V_{\text{actual}} - M \cdot (1 - \beta_{\text{invest}}(s)) \quad \forall s \in \{1,2,\ldots,S\} | ||||||||||
| \end{aligned} | ||||||||||
| $$ | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| ### Usecase 3: Find the best scenario to increment the size (Timing of the investment) | ||||||||||
| The size can only increment once (based on a starting point). This allows to optimize the timing of an investment. | ||||||||||
| #### Math | ||||||||||
| Treat $\beta_{invest}$ like an ON/OFF variable, and introduce a SwitchOn, that can only be active once. | ||||||||||
|
|
||||||||||
| *Thoughts:* | ||||||||||
| - Treating $\beta_{invest}$ like an ON/OFF variable suggest using the already presentconstraints linked to On/OffModel | ||||||||||
|
Comment on lines
+95
to
+96
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix typo in "present constraints" Line 96 contains a typo: "presentconstraints" should be "present constraints". -- Treating $\beta_{invest}$ like an ON/OFF variable suggest using the already presentconstraints linked to On/OffModel
+- Treating $\beta_{invest}$ like an ON/OFF variable suggests using the already present constraints linked to On/OffModel📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| - The timing could be constraint to be first in scenario x, or last in scenario y | ||||||||||
| - Restrict the number of consecutive scenarios | ||||||||||
| 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) | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix typo in "This" Line 99 contains a typo: "THis" should be "This". -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)
+This might need 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 measurable (integers)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
|
|
||||||||||
| ### Others | ||||||||||
|
|
||||||||||
| #### Usecase 4: Only increase/decrease the size | ||||||||||
| Start from a certain size. For each scenario, the size can increase, but never decrease. (Or the other way around). | ||||||||||
| This would mean that a size expansion is possible, | ||||||||||
|
|
||||||||||
| #### Usecase 5: Restrict the increment in size per scenario | ||||||||||
| Restrict how much the size can increase/decrease for in scenario, based on the prior scenario. | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| Many more are possible | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -66,7 +66,8 @@ | |||||||||
| discharging=fx.Flow('Q_th_unload', bus='Fernwärme', size=1000), | ||||||||||
| capacity_in_flow_hours=fx.InvestParameters(fix_effects=20, fixed_size=30, optional=False), | ||||||||||
| initial_charge_state=0, # Initial storage state: empty | ||||||||||
| relative_maximum_charge_state=1 / 100 * np.array([80, 70, 80, 80, 80, 80, 80, 80, 80, 80]), | ||||||||||
| relative_maximum_charge_state=1 / 100 * np.array([80, 70, 80, 80, 80, 80, 80, 80, 80]), | ||||||||||
| relative_maximum_final_charge_state=0.8, | ||||||||||
|
Comment on lines
+69
to
+70
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Storage parameter array size inconsistency detected The Apply this fix to align with the new API: - relative_maximum_charge_state=1 / 100 * np.array([80, 70, 80, 80, 80, 80, 80, 80, 80]),
+ relative_maximum_charge_state=1 / 100 * np.array([80, 70, 80, 80, 80, 80, 80, 80]),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| eta_charge=0.9, | ||||||||||
| eta_discharge=1, # Efficiency factors for charging/discharging | ||||||||||
| relative_loss_per_hour=0.08, # 8% loss per hour. Absolute loss depends on current charge state | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,9 +45,9 @@ | |||||||||||||
|
|
||||||||||||||
| # TimeSeriesData objects | ||||||||||||||
| TS_heat_demand = fx.TimeSeriesData(heat_demand) | ||||||||||||||
| TS_electricity_demand = fx.TimeSeriesData(electricity_demand, agg_weight=0.7) | ||||||||||||||
| TS_electricity_price_sell = fx.TimeSeriesData(-(electricity_demand - 0.5), agg_group='p_el') | ||||||||||||||
| TS_electricity_price_buy = fx.TimeSeriesData(electricity_price + 0.5, agg_group='p_el') | ||||||||||||||
| TS_electricity_demand = fx.TimeSeriesData(electricity_demand, aggregation_weight=0.7) | ||||||||||||||
| TS_electricity_price_sell = fx.TimeSeriesData(-(electricity_demand - 0.5), aggregation_group='p_el') | ||||||||||||||
| TS_electricity_price_buy = fx.TimeSeriesData(electricity_price + 0.5, aggregation_group='p_el') | ||||||||||||||
|
Comment on lines
+48
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use electricity_price for sell tariff; demand is incorrect here. Sell price should be derived from price, not demand. -TS_electricity_demand = fx.TimeSeriesData(electricity_demand, aggregation_weight=0.7)
-TS_electricity_price_sell = fx.TimeSeriesData(-(electricity_demand - 0.5), aggregation_group='p_el')
-TS_electricity_price_buy = fx.TimeSeriesData(electricity_price + 0.5, aggregation_group='p_el')
+TS_electricity_demand = fx.TimeSeriesData(electricity_demand, aggregation_weight=0.7)
+TS_electricity_price_sell = fx.TimeSeriesData(-(electricity_price - 0.5), aggregation_group='p_el')
+TS_electricity_price_buy = fx.TimeSeriesData(electricity_price + 0.5, aggregation_group='p_el')📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| flow_system = fx.FlowSystem(timesteps) | ||||||||||||||
| flow_system.add_elements( | ||||||||||||||
|
|
@@ -161,12 +161,12 @@ | |||||||||||||
| if full: | ||||||||||||||
| calculation = fx.FullCalculation('Full', flow_system) | ||||||||||||||
| calculation.do_modeling() | ||||||||||||||
| calculation.solve(fx.solvers.HighsSolver(0, 60)) | ||||||||||||||
| calculation.solve(fx.solvers.HighsSolver(0.01 / 100, 60)) | ||||||||||||||
| calculations.append(calculation) | ||||||||||||||
|
|
||||||||||||||
| if segmented: | ||||||||||||||
| calculation = fx.SegmentedCalculation('Segmented', flow_system, segment_length, overlap_length) | ||||||||||||||
| calculation.do_modeling_and_solve(fx.solvers.HighsSolver(0, 60)) | ||||||||||||||
| calculation.do_modeling_and_solve(fx.solvers.HighsSolver(0.01 / 100, 60)) | ||||||||||||||
| calculations.append(calculation) | ||||||||||||||
|
|
||||||||||||||
| if aggregated: | ||||||||||||||
|
|
@@ -175,7 +175,7 @@ | |||||||||||||
| aggregation_parameters.time_series_for_low_peaks = [TS_electricity_demand, TS_heat_demand] | ||||||||||||||
| calculation = fx.AggregatedCalculation('Aggregated', flow_system, aggregation_parameters) | ||||||||||||||
| calculation.do_modeling() | ||||||||||||||
| calculation.solve(fx.solvers.HighsSolver(0, 60)) | ||||||||||||||
| calculation.solve(fx.solvers.HighsSolver(0.01 / 100, 60)) | ||||||||||||||
| calculations.append(calculation) | ||||||||||||||
|
|
||||||||||||||
| # Get solutions for plotting for different calculations | ||||||||||||||
|
|
@@ -191,34 +191,35 @@ def get_solutions(calcs: list, variable: str) -> xr.Dataset: | |||||||||||||
| # --- Plotting for comparison --- | ||||||||||||||
| fx.plotting.with_plotly( | ||||||||||||||
| get_solutions(calculations, 'Speicher|charge_state').to_dataframe(), | ||||||||||||||
| mode='line', | ||||||||||||||
| style='line', | ||||||||||||||
| title='Charge State Comparison', | ||||||||||||||
| ylabel='Charge state', | ||||||||||||||
| ).write_html('results/Charge State.html') | ||||||||||||||
|
|
||||||||||||||
|
Comment on lines
191
to
198
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Ensure output folder exists before writing HTML files. Avoids FileNotFoundError when 'results/' is missing. # --- Plotting for comparison ---
- fx.plotting.with_plotly(
+ pathlib.Path('results').mkdir(parents=True, exist_ok=True)
+ fx.plotting.with_plotly(
get_solutions(calculations, 'Speicher|charge_state').to_dataframe(),
style='line',
title='Charge State Comparison',
ylabel='Charge state',
).write_html('results/Charge State.html')
🤖 Prompt for AI Agents |
||||||||||||||
| fx.plotting.with_plotly( | ||||||||||||||
| get_solutions(calculations, 'BHKW2(Q_th)|flow_rate').to_dataframe(), | ||||||||||||||
| mode='line', | ||||||||||||||
| style='line', | ||||||||||||||
| title='BHKW2(Q_th) Flow Rate Comparison', | ||||||||||||||
| ylabel='Flow rate', | ||||||||||||||
| ).write_html('results/BHKW2 Thermal Power.html') | ||||||||||||||
|
|
||||||||||||||
| fx.plotting.with_plotly( | ||||||||||||||
| get_solutions(calculations, 'costs(operation)|total_per_timestep').to_dataframe(), | ||||||||||||||
| mode='line', | ||||||||||||||
| style='line', | ||||||||||||||
| title='Operation Cost Comparison', | ||||||||||||||
| ylabel='Costs [€]', | ||||||||||||||
| ).write_html('results/Operation Costs.html') | ||||||||||||||
|
|
||||||||||||||
| fx.plotting.with_plotly( | ||||||||||||||
| pd.DataFrame(get_solutions(calculations, 'costs(operation)|total_per_timestep').to_dataframe().sum()).T, | ||||||||||||||
| mode='bar', | ||||||||||||||
| style='stacked_bar', | ||||||||||||||
| title='Total Cost Comparison', | ||||||||||||||
| ylabel='Costs [€]', | ||||||||||||||
| ).update_layout(barmode='group').write_html('results/Total Costs.html') | ||||||||||||||
|
|
||||||||||||||
| fx.plotting.with_plotly( | ||||||||||||||
| pd.DataFrame([calc.durations for calc in calculations], index=[calc.name for calc in calculations]), 'bar' | ||||||||||||||
| pd.DataFrame([calc.durations for calc in calculations], index=[calc.name for calc in calculations]), | ||||||||||||||
| 'stacked_bar', | ||||||||||||||
| ).update_layout(title='Duration Comparison', xaxis_title='Calculation type', yaxis_title='Time (s)').write_html( | ||||||||||||||
| 'results/Speed Comparison.html' | ||||||||||||||
| ) | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typo in "whether"
Line 12 contains a typo: "wether" should be "whether".
📝 Committable suggestion
🤖 Prompt for AI Agents