flixopt 2.1.0__tar.gz → 2.1.1__tar.gz
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.
- {flixopt-2.1.0 → flixopt-2.1.1}/PKG-INFO +1 -1
- flixopt-2.1.1/docs/release-notes/v2.1.1.md +11 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/components.py +4 -1
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/elements.py +4 -3
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/results.py +1 -1
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt.egg-info/PKG-INFO +1 -1
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt.egg-info/SOURCES.txt +1 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/conftest.py +1 -1
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_flow.py +137 -2
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_storage.py +1 -1
- {flixopt-2.1.0 → flixopt-2.1.1}/.github/workflows/deploy-docs.yaml +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/.github/workflows/python-app.yaml +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/.gitignore +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/LICENSE +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/README.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/SUMMARY.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/contribute.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/examples/00-Minimal Example.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/examples/01-Basic Example.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/examples/02-Complex Example.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/examples/03-Calculation Modes.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/examples/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/faq/contribute.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/faq/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/getting-started.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/images/architecture_flixOpt-pre2.0.0.png +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/images/architecture_flixOpt.png +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/images/flixopt-icon.svg +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/javascripts/mathjax.js +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/release-notes/_template.txt +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/release-notes/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/release-notes/v2.0.0.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/release-notes/v2.0.1.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/release-notes/v2.1.0.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/Bus.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/Flow.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/LinearConverter.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/Piecewise.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/Storage.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/Mathematical Notation/others.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/docs/user-guide/index.md +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/00_Minmal/minimal_example.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/01_Simple/simple_example.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/02_Complex/complex_example.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/02_Complex/complex_example_results.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/03_Calculation_types/Zeitreihen2020.csv +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/examples/03_Calculation_types/example_calculation_types.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/__init__.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/aggregation.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/calculation.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/commons.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/config.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/config.yaml +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/core.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/effects.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/features.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/flow_system.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/interface.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/io.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/linear_converters.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/plotting.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/solvers.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/structure.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt/utils.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt.egg-info/dependency_links.txt +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt.egg-info/requires.txt +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/flixopt.egg-info/top_level.txt +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/mkdocs.yml +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pics/architecture_flixOpt-pre2.0.0.png +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pics/architecture_flixOpt.png +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pics/flixOpt_plotting.jpg +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pics/flixopt-icon.svg +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pics/pics.pptx +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/pyproject.toml +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/scripts/gen_ref_pages.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/setup.cfg +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/site/release-notes/_template.txt +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/__init__.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/ressources/Zeitreihen2020.csv +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/run_all_tests.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_bus.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_component.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_dataconverter.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_effect.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_examples.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_functional.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_integration.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_io.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_linear_converter.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_on_hours_computation.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_plots.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_results_plots.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/test_timeseries.py +0 -0
- {flixopt-2.1.0 → flixopt-2.1.1}/tests/todos.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flixopt
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: Vector based energy and material flow optimization framework in Python.
|
|
5
5
|
Author-email: "Chair of Building Energy Systems and Heat Supply, TU Dresden" <peter.stange@tu-dresden.de>, Felix Bumann <felixbumann387@gmail.com>, Felix Panitz <baumbude@googlemail.com>, Peter Stange <peter.stange@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Felix Bumann <felixbumann387@gmail.com>, Peter Stange <peter.stange@tu-dresden.de>
|
|
@@ -43,7 +43,10 @@ class LinearConverter(Component):
|
|
|
43
43
|
label: The label of the Element. Used to identify it in the FlowSystem
|
|
44
44
|
inputs: The input Flows
|
|
45
45
|
outputs: The output Flows
|
|
46
|
-
on_off_parameters: Information about on and off
|
|
46
|
+
on_off_parameters: Information about on and off state of LinearConverter.
|
|
47
|
+
Component is On/Off, if all connected Flows are On/Off. This induces an On-Variable (binary) in all Flows!
|
|
48
|
+
If possible, use OnOffParameters in a single Flow instead to keep the number of binary variables low.
|
|
49
|
+
See class OnOffParameters.
|
|
47
50
|
conversion_factors: linear relation between flows.
|
|
48
51
|
Either 'conversion_factors' or 'piecewise_conversion' can be used!
|
|
49
52
|
piecewise_conversion: Define a piecewise linear relation between flow rates of different flows.
|
|
@@ -47,8 +47,8 @@ class Component(Element):
|
|
|
47
47
|
inputs: input flows.
|
|
48
48
|
outputs: output flows.
|
|
49
49
|
on_off_parameters: Information about on and off state of Component.
|
|
50
|
-
Component is On/Off, if all connected Flows are On/Off.
|
|
51
|
-
|
|
50
|
+
Component is On/Off, if all connected Flows are On/Off. This induces an On-Variable (binary) in all Flows!
|
|
51
|
+
If possible, use OnOffParameters in a single Flow instead to keep the number of binary variables low.
|
|
52
52
|
See class OnOffParameters.
|
|
53
53
|
prevent_simultaneous_flows: Define a Group of Flows. Only one them can be on at a time.
|
|
54
54
|
Induces On-Variable in all Flows! If possible, use OnOffParameters in a single Flow instead.
|
|
@@ -193,7 +193,8 @@ class Flow(Element):
|
|
|
193
193
|
(relative_minimum and relative_maximum are ignored)
|
|
194
194
|
used for fixed load or supply profiles, i.g. heat demand, wind-power, solarthermal
|
|
195
195
|
If the load-profile is just an upper limit, use relative_maximum instead.
|
|
196
|
-
previous_flow_rate: previous flow rate of the
|
|
196
|
+
previous_flow_rate: previous flow rate of the flow. Used to determine if and how long the
|
|
197
|
+
flow is already on / off. If None, the flow is considered to be off for one timestep.
|
|
197
198
|
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
198
199
|
"""
|
|
199
200
|
super().__init__(label, meta_data=meta_data)
|
|
@@ -343,7 +343,7 @@ class _ElementResults:
|
|
|
343
343
|
"""
|
|
344
344
|
if self._calculation_results.model is None:
|
|
345
345
|
raise ValueError('The linopy model is not available.')
|
|
346
|
-
return self._calculation_results.model.constraints[self.
|
|
346
|
+
return self._calculation_results.model.constraints[self._constraint_names]
|
|
347
347
|
|
|
348
348
|
def filter_solution(self, variable_dims: Optional[Literal['scalar', 'time']] = None) -> xr.Dataset:
|
|
349
349
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flixopt
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: Vector based energy and material flow optimization framework in Python.
|
|
5
5
|
Author-email: "Chair of Building Energy Systems and Heat Supply, TU Dresden" <peter.stange@tu-dresden.de>, Felix Bumann <felixbumann387@gmail.com>, Felix Panitz <baumbude@googlemail.com>, Peter Stange <peter.stange@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Felix Bumann <felixbumann387@gmail.com>, Peter Stange <peter.stange@tu-dresden.de>
|
|
@@ -25,6 +25,7 @@ docs/release-notes/index.md
|
|
|
25
25
|
docs/release-notes/v2.0.0.md
|
|
26
26
|
docs/release-notes/v2.0.1.md
|
|
27
27
|
docs/release-notes/v2.1.0.md
|
|
28
|
+
docs/release-notes/v2.1.1.md
|
|
28
29
|
docs/user-guide/index.md
|
|
29
30
|
docs/user-guide/Mathematical Notation/Bus.md
|
|
30
31
|
docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md
|
|
@@ -432,7 +432,7 @@ def timesteps_linopy(request):
|
|
|
432
432
|
@pytest.fixture
|
|
433
433
|
def basic_flow_system_linopy(timesteps_linopy) -> fx.FlowSystem:
|
|
434
434
|
"""Create basic elements for component testing"""
|
|
435
|
-
flow_system = fx.FlowSystem(
|
|
435
|
+
flow_system = fx.FlowSystem(timesteps_linopy)
|
|
436
436
|
thermal_load = np.array([np.random.random() for _ in range(10)]) * 180
|
|
437
437
|
p_el = (np.array([np.random.random() for _ in range(10)]) + 0.5) / 1.5 * 50
|
|
438
438
|
|
|
@@ -616,6 +616,73 @@ class TestFlowOnModel:
|
|
|
616
616
|
>= (model.variables['Sink(Wärme)|on'].isel(time=slice(None, -1)) - model.variables['Sink(Wärme)|on'].isel(time=slice(1, None))) * 2
|
|
617
617
|
)
|
|
618
618
|
|
|
619
|
+
def test_consecutive_on_hours_previous(self, basic_flow_system_linopy):
|
|
620
|
+
"""Test flow with minimum and maximum consecutive on hours."""
|
|
621
|
+
flow_system = basic_flow_system_linopy
|
|
622
|
+
timesteps = flow_system.time_series_collection.timesteps
|
|
623
|
+
|
|
624
|
+
flow = fx.Flow(
|
|
625
|
+
'Wärme',
|
|
626
|
+
bus='Fernwärme',
|
|
627
|
+
size=100,
|
|
628
|
+
on_off_parameters=fx.OnOffParameters(
|
|
629
|
+
consecutive_on_hours_min=2, # Must run for at least 2 hours when turned on
|
|
630
|
+
consecutive_on_hours_max=8, # Can't run more than 8 consecutive hours
|
|
631
|
+
),
|
|
632
|
+
previous_flow_rate=np.array([10, 20, 30, 0, 20, 20, 30]) # Previously on for 3 steps
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
flow_system.add_elements( fx.Sink('Sink', sink=flow))
|
|
636
|
+
model = create_linopy_model(flow_system)
|
|
637
|
+
|
|
638
|
+
assert {'Sink(Wärme)|ConsecutiveOn|hours', 'Sink(Wärme)|on'}.issubset(set(flow.model.variables))
|
|
639
|
+
|
|
640
|
+
assert {'Sink(Wärme)|ConsecutiveOn|con1',
|
|
641
|
+
'Sink(Wärme)|ConsecutiveOn|con2a',
|
|
642
|
+
'Sink(Wärme)|ConsecutiveOn|con2b',
|
|
643
|
+
'Sink(Wärme)|ConsecutiveOn|initial',
|
|
644
|
+
'Sink(Wärme)|ConsecutiveOn|minimum',
|
|
645
|
+
}.issubset(set(flow.model.constraints))
|
|
646
|
+
|
|
647
|
+
assert_var_equal(
|
|
648
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours'],
|
|
649
|
+
model.add_variables(lower=0, upper=8, coords=(timesteps,))
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 3
|
|
653
|
+
|
|
654
|
+
assert_conequal(
|
|
655
|
+
model.constraints['Sink(Wärme)|ConsecutiveOn|con1'],
|
|
656
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours'] <= model.variables['Sink(Wärme)|on'] * mega
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
assert_conequal(
|
|
660
|
+
model.constraints['Sink(Wärme)|ConsecutiveOn|con2a'],
|
|
661
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours'].isel(time=slice(1, None))
|
|
662
|
+
<= model.variables['Sink(Wärme)|ConsecutiveOn|hours'].isel(time=slice(None, -1)) + model.hours_per_step.isel(time=slice(None, -1))
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
|
|
666
|
+
assert_conequal(
|
|
667
|
+
model.constraints['Sink(Wärme)|ConsecutiveOn|con2b'],
|
|
668
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours'].isel(time=slice(1, None))
|
|
669
|
+
>= model.variables['Sink(Wärme)|ConsecutiveOn|hours'].isel(time=slice(None, -1))
|
|
670
|
+
+ model.hours_per_step.isel(time=slice(None, -1))
|
|
671
|
+
+ (model.variables['Sink(Wärme)|on'].isel(time=slice(1, None)) - 1) * mega
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
assert_conequal(
|
|
675
|
+
model.constraints['Sink(Wärme)|ConsecutiveOn|initial'],
|
|
676
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours'].isel(time=0)
|
|
677
|
+
== model.variables['Sink(Wärme)|on'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 3)),
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
assert_conequal(
|
|
681
|
+
model.constraints['Sink(Wärme)|ConsecutiveOn|minimum'],
|
|
682
|
+
model.variables['Sink(Wärme)|ConsecutiveOn|hours']
|
|
683
|
+
>= (model.variables['Sink(Wärme)|on'].isel(time=slice(None, -1)) - model.variables['Sink(Wärme)|on'].isel(time=slice(1, None))) * 2
|
|
684
|
+
)
|
|
685
|
+
|
|
619
686
|
def test_consecutive_off_hours(self, basic_flow_system_linopy):
|
|
620
687
|
"""Test flow with minimum and maximum consecutive off hours."""
|
|
621
688
|
flow_system = basic_flow_system_linopy
|
|
@@ -649,7 +716,75 @@ class TestFlowOnModel:
|
|
|
649
716
|
model.add_variables(lower=0, upper=12, coords=(timesteps,))
|
|
650
717
|
)
|
|
651
718
|
|
|
652
|
-
mega = model.hours_per_step.sum('time') + 1 # previously off for 1h
|
|
719
|
+
mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 1 # previously off for 1h
|
|
720
|
+
|
|
721
|
+
assert_conequal(
|
|
722
|
+
model.constraints['Sink(Wärme)|ConsecutiveOff|con1'],
|
|
723
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours'] <= model.variables['Sink(Wärme)|off'] * mega
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
assert_conequal(
|
|
727
|
+
model.constraints['Sink(Wärme)|ConsecutiveOff|con2a'],
|
|
728
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=slice(1, None))
|
|
729
|
+
<= model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=slice(None, -1)) + model.hours_per_step.isel(time=slice(None, -1))
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
|
|
733
|
+
assert_conequal(
|
|
734
|
+
model.constraints['Sink(Wärme)|ConsecutiveOff|con2b'],
|
|
735
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=slice(1, None))
|
|
736
|
+
>= model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=slice(None, -1))
|
|
737
|
+
+ model.hours_per_step.isel(time=slice(None, -1))
|
|
738
|
+
+ (model.variables['Sink(Wärme)|off'].isel(time=slice(1, None)) - 1) * mega
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
assert_conequal(
|
|
742
|
+
model.constraints['Sink(Wärme)|ConsecutiveOff|initial'],
|
|
743
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=0)
|
|
744
|
+
== model.variables['Sink(Wärme)|off'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 1)),
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
assert_conequal(
|
|
748
|
+
model.constraints['Sink(Wärme)|ConsecutiveOff|minimum'],
|
|
749
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours']
|
|
750
|
+
>= (model.variables['Sink(Wärme)|off'].isel(time=slice(None, -1)) - model.variables['Sink(Wärme)|off'].isel(time=slice(1, None))) * 4
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
def test_consecutive_off_hours_previous(self, basic_flow_system_linopy):
|
|
754
|
+
"""Test flow with minimum and maximum consecutive off hours."""
|
|
755
|
+
flow_system = basic_flow_system_linopy
|
|
756
|
+
timesteps = flow_system.time_series_collection.timesteps
|
|
757
|
+
|
|
758
|
+
flow = fx.Flow(
|
|
759
|
+
'Wärme',
|
|
760
|
+
bus='Fernwärme',
|
|
761
|
+
size=100,
|
|
762
|
+
on_off_parameters=fx.OnOffParameters(
|
|
763
|
+
consecutive_off_hours_min=4, # Must stay off for at least 4 hours when shut down
|
|
764
|
+
consecutive_off_hours_max=12, # Can't be off for more than 12 consecutive hours
|
|
765
|
+
),
|
|
766
|
+
previous_flow_rate=np.array([10, 20, 30, 0, 20, 0, 0]) # Previously off for 2 steps
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
flow_system.add_elements( fx.Sink('Sink', sink=flow))
|
|
770
|
+
model = create_linopy_model(flow_system)
|
|
771
|
+
|
|
772
|
+
assert {'Sink(Wärme)|ConsecutiveOff|hours', 'Sink(Wärme)|off'}.issubset(set(flow.model.variables))
|
|
773
|
+
|
|
774
|
+
assert {
|
|
775
|
+
'Sink(Wärme)|ConsecutiveOff|con1',
|
|
776
|
+
'Sink(Wärme)|ConsecutiveOff|con2a',
|
|
777
|
+
'Sink(Wärme)|ConsecutiveOff|con2b',
|
|
778
|
+
'Sink(Wärme)|ConsecutiveOff|initial',
|
|
779
|
+
'Sink(Wärme)|ConsecutiveOff|minimum'
|
|
780
|
+
}.issubset(set(flow.model.constraints))
|
|
781
|
+
|
|
782
|
+
assert_var_equal(
|
|
783
|
+
model.variables['Sink(Wärme)|ConsecutiveOff|hours'],
|
|
784
|
+
model.add_variables(lower=0, upper=12, coords=(timesteps,))
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 2
|
|
653
788
|
|
|
654
789
|
assert_conequal(
|
|
655
790
|
model.constraints['Sink(Wärme)|ConsecutiveOff|con1'],
|
|
@@ -674,7 +809,7 @@ class TestFlowOnModel:
|
|
|
674
809
|
assert_conequal(
|
|
675
810
|
model.constraints['Sink(Wärme)|ConsecutiveOff|initial'],
|
|
676
811
|
model.variables['Sink(Wärme)|ConsecutiveOff|hours'].isel(time=0)
|
|
677
|
-
== model.variables['Sink(Wärme)|off'].isel(time=0) * (model.hours_per_step.isel(time=0)+
|
|
812
|
+
== model.variables['Sink(Wärme)|off'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1+2)),
|
|
678
813
|
)
|
|
679
814
|
|
|
680
815
|
assert_conequal(
|
|
@@ -78,7 +78,7 @@ class TestStorageModel:
|
|
|
78
78
|
assert_conequal(
|
|
79
79
|
model.constraints['TestStorage|charge_state'],
|
|
80
80
|
charge_state.isel(time=slice(1, None))
|
|
81
|
-
== charge_state.isel(time=slice(None, -1))
|
|
81
|
+
== charge_state.isel(time=slice(None, -1))
|
|
82
82
|
+ model.variables['TestStorage(Q_th_in)|flow_rate'] * model.hours_per_step
|
|
83
83
|
- model.variables['TestStorage(Q_th_out)|flow_rate'] * model.hours_per_step,
|
|
84
84
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|