Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Until here -->
### Fixed
- Fix color scheme selection in network_app; color pickers now update when a scheme is selected.
- Fix error handling in network visualization if networkx is not installed.
- Fix broken links in docs.
- Fix missing args in docstrings in `plotting.py`, `solvers.py`, and `core.py`.

### Known Issues

Expand Down
2 changes: 1 addition & 1 deletion docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
- [User Guide](user-guide/)
- [Examples](examples/)
- [Contribute](contribute.md)
- [API-Reference](api-reference/)
- [API Reference](api-reference/)
- [Release Notes](changelog.md)
4 changes: 2 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This provides the core functionality with the HiGHS solver included.
For all features including interactive network visualizations and time series aggregation:

```bash
pip install "flixopt[full]""
pip install "flixopt[full]"
```

## Basic Workflow
Expand All @@ -38,5 +38,5 @@ Working with FlixOpt follows a general pattern:
Now that you've installed FlixOpt and understand the basic workflow, you can:

- Learn about the [core concepts of FlixOpt](user-guide/index.md)
- Explore some [examples](examples/)
- Explore some [examples](examples/index.md)
- Check the [API reference](api-reference/index.md) for detailed documentation
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## Effects
[`Effects`][flixopt.effects.Effect] are used to allocate things like costs, emissions, or other "effects" occuring in the system.
[`Effects`][flixopt.effects.Effect] are used to allocate things like costs, emissions, or other "effects" occurring in the system.
These arise from so called **Shares**, which originate from **Elements** like [Flows](Flow.md).

**Example:**

[`Flows`][flixopt.elements.Flow] have an attribute called `effects_per_flow_hour`, defining the effect amount of per flow hour.
Assiziated effects could be:
Associated effects could be:
- costs - given in [€/kWh]...
- ...or emissions - given in [kg/kWh].
-
Effects are allocated seperatly for investments and operation.
Effects are allocated separately for investments and operation.

### Shares to Effects

Expand Down Expand Up @@ -43,7 +43,7 @@ For example, the Effect "CO$_2$ emissions" (unit: kg)
can cause an additional share to Effect "monetary costs" (unit: €).
In this case, the factor $\text a_{x \rightarrow e}$ is the specific CO$_2$ price in €/kg. However, circular references have to be avoided.

The overall sum of investment shares of an Effect $e$ is given by $\eqref{Effect_invest}$
The overall sum of investment shares of an Effect $e$ is given by $\eqref{eq:Effect_invest}$

$$ \label{eq:Effect_invest}
E_{e, \text{inv}} =
Expand All @@ -68,8 +68,8 @@ With:

- $\mathcal{L}$ being the set of all elements in the FlowSystem
- $\mathcal{E}$ being the set of all effects in the FlowSystem
- $\text r_{x \rightarrow e, \text{inv}}$ being the factor between the operation part of Effect $x$ and Effect $e$
- $\text r_{x \rightarrow e, \text{op}}(\text{t}_i)$ being the factor between the invest part of Effect $x$ and Effect $e$
- $\text r_{x \rightarrow e, \text{inv}}$ being the factor between the invest part of Effect $x$ and Effect $e$
- $\text r_{x \rightarrow e, \text{op}}(\text{t}_i)$ being the factor between the operation part of Effect $x$ and Effect $e$

- $\text{t}_i$ being the time step
- $s_{l \rightarrow e, \text{inv}}$ being the share of element $l$ to the investment part of effect $e$
Expand Down Expand Up @@ -113,7 +113,7 @@ With:
- $\mathcal{T}$ being the set of all timesteps
- $s_{l \rightarrow \Phi}$ being the share of element $l$ to the penalty

At the moment, penalties only occur in [Buses](#buses)
At the moment, penalties only occur in [Buses](Bus.md)

## Objective

Expand All @@ -128,5 +128,5 @@ With:
- $\Phi$ being the [Penalty](#penalty)

This approach allows for a multi-criteria optimization using both...
- ... the **Weigted Sum**Method, as the chosen **Objective Effect** can incorporate other Effects.
- ... the **Weighted Sum** method, as the chosen **Objective Effect** can incorporate other Effects.
- ... the ($\epsilon$-constraint method) by constraining effects.
6 changes: 3 additions & 3 deletions docs/user-guide/Mathematical Notation/Flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ $$
$$


This mathematical Formulation can be extended or changed when using [OnOffParameters](#onoffparameters)
to define the On/Off state of the Flow, or [InvestParameters](#investments),
which changes the size of the Flow from a constant to an optimization variable.
This mathematical formulation can be extended by using [OnOffParameters](./OnOffParameters.md)
to define the on/off state of the Flow, or by using [InvestParameters](./InvestParameters.md)
to change the size of the Flow from a constant to an optimization variable.
3 changes: 3 additions & 0 deletions docs/user-guide/Mathematical Notation/InvestParameters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# InvestParameters

This is a work in progress.
6 changes: 3 additions & 3 deletions docs/user-guide/Mathematical Notation/LinearConverter.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[`LinearConverters`][flixopt.components.LinearConverter] define a ratio between incoming and outgoing [Flows](#flows).
[`LinearConverters`][flixopt.components.LinearConverter] define a ratio between incoming and outgoing [Flows](Flow.md).

$$ \label{eq:Linear-Transformer-Ratio}
\sum_{f_{\text{in}} \in \mathcal F_{in}} \text a_{f_{\text{in}}}(\text{t}_i) \cdot p_{f_\text{in}}(\text{t}_i) = \sum_{f_{\text{out}} \in \mathcal F_{out}} \text b_{f_\text{out}}(\text{t}_i) \cdot p_{f_\text{out}}(\text{t}_i)
Expand All @@ -16,6 +16,6 @@ $$ \label{eq:Linear-Transformer-Ratio-simple}
\text a(\text{t}_i) \cdot p_{f_\text{in}}(\text{t}_i) = p_{f_\text{out}}(\text{t}_i)
$$

where $\text a$ can be interpreted as the conversion efficiency of the **LinearTransformer**.
#### Piecewise Concersion factors
where $\text a$ can be interpreted as the conversion efficiency of the **LinearConverter**.
#### Piecewise Conversion factors
The conversion efficiency can be defined as a piecewise linear approximation. See [Piecewise](Piecewise.md) for more details.
3 changes: 3 additions & 0 deletions docs/user-guide/Mathematical Notation/OnOffParameters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# OnOffParameters

This is a work in progress.
2 changes: 1 addition & 1 deletion docs/user-guide/Mathematical Notation/Storage.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Storages
**Storages** have one incoming and one outgoing **[Flow](#flows)** with a charging and discharging efficiency.
**Storages** have one incoming and one outgoing **[Flow](Flow.md)** with a charging and discharging efficiency.
A storage has a state of charge $c(\text{t}_i)$ which is limited by its `size` $\text C$ and relative bounds $\eqref{eq:Storage_Bounds}$.

$$ \label{eq:Storage_Bounds}
Expand Down
1 change: 0 additions & 1 deletion flixopt/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,6 @@ def create_time_series(
data: The data to create the TimeSeries from.
name: The name of the TimeSeries.
needs_extra_timestep: Whether to create an additional timestep at the end of the timesteps.
The data to create the TimeSeries from.

Returns:
The created TimeSeries.
Expand Down
24 changes: 14 additions & 10 deletions flixopt/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ def with_plotly(
- A dictionary mapping column names to colors (e.g., {'Column1': '#ff0000'})
title: The title of the plot.
ylabel: The label for the y-axis.
xlabel: The label for the x-axis.
fig: A Plotly figure object to plot on. If not provided, a new figure will be created.

Returns:
Expand Down Expand Up @@ -455,6 +456,9 @@ def heat_map_matplotlib(
data: A DataFrame containing the data to be visualized. The index will be used for the y-axis, and columns will be used for the x-axis.
The values in the DataFrame will be represented as colors in the heatmap.
color_map: The colormap to use for the heatmap. Default is 'viridis'. Matplotlib supports various colormaps like 'plasma', 'inferno', 'cividis', etc.
title: The title of the plot.
xlabel: The label for the x-axis.
ylabel: The label for the y-axis.
figsize: The size of the figure to create. Default is (12, 6), which results in a width of 12 inches and a height of 6 inches.

Returns:
Expand Down Expand Up @@ -517,11 +521,11 @@ def heat_map_plotly(
data: A DataFrame with the data to be visualized. The index will be used for the y-axis, and columns will be used for the x-axis.
The values in the DataFrame will be represented as colors in the heatmap.
color_map: The color scale to use for the heatmap. Default is 'viridis'. Plotly supports various color scales like 'Cividis', 'Inferno', etc.
title: The title of the heatmap. Default is an empty string.
xlabel: The label for the x-axis. Default is 'Period'.
ylabel: The label for the y-axis. Default is 'Step'.
categorical_labels: If True, the x and y axes are treated as categorical data (i.e., the index and columns will not be interpreted as continuous data).
Default is True. If False, the axes are treated as continuous, which may be useful for time series or numeric data.
show: Wether to show the figure after creation. (This includes saving the figure)
save: Wether to save the figure after creation (without showing)
path: Path to save the figure.

Returns:
A Plotly figure object containing the heatmap. This can be further customized and saved
Expand Down Expand Up @@ -617,7 +621,7 @@ def heat_map_data_from_df(
"""
Reshapes a DataFrame with a DateTime index into a 2D array for heatmap plotting,
based on a specified sample rate.
If a non-valid combination of periods and steps per period is used, falls back to numerical indices
Only specific combinations of `periods` and `steps_per_period` are supported; invalid combinations raise an assertion.

Args:
df: A DataFrame with a DateTime index containing the data to reshape.
Expand All @@ -632,7 +636,7 @@ def heat_map_data_from_df(
and columns representing each period.
"""
assert pd.api.types.is_datetime64_any_dtype(df.index), (
'The index of the Dataframe must be datetime to transfrom it properly for a heatmap plot'
'The index of the DataFrame must be datetime to transform it properly for a heatmap plot'
)

# Define formats for different combinations of `periods` and `steps_per_period`
Expand All @@ -645,15 +649,15 @@ def heat_map_data_from_df(
('W', 'D'): ('%Y-w%W', '%w_%A'), # week and day of week (with prefix for proper sorting)
('W', 'h'): ('%Y-w%W', '%w_%A %H:00'),
('D', 'h'): ('%Y-%m-%d', '%H:00'), # Day and hour
('D', '15min'): ('%Y-%m-%d', '%H:%MM'), # Day and hour
('D', '15min'): ('%Y-%m-%d', '%H:%M'), # Day and minute
('h', '15min'): ('%Y-%m-%d %H:00', '%M'), # minute of hour
('h', 'min'): ('%Y-%m-%d %H:00', '%M'), # minute of hour
}

minimum_time_diff_in_min = df.index.to_series().diff().min().total_seconds() / 60 # Smallest time_diff in minutes
diffs = df.index.to_series().diff().dropna()
minimum_time_diff_in_min = diffs.min().total_seconds() / 60
time_intervals = {'min': 1, '15min': 15, 'h': 60, 'D': 24 * 60, 'W': 7 * 24 * 60}
if time_intervals[steps_per_period] > minimum_time_diff_in_min:
time_intervals[steps_per_period]
logger.warning(
f'To compute the heatmap, the data was aggregated from {minimum_time_diff_in_min:.2f} min to '
f'{time_intervals[steps_per_period]:.2f} min. Mean values are displayed.'
Expand All @@ -675,7 +679,7 @@ def heat_map_data_from_df(

resampled_data['period'] = resampled_data.index.strftime(period_format)
resampled_data['step'] = resampled_data.index.strftime(step_format)
if '%w_%A' in step_format: # SHift index of strings to ensure proper sorting
if '%w_%A' in step_format: # Shift index of strings to ensure proper sorting
resampled_data['step'] = resampled_data['step'].apply(
lambda x: x.replace('0_Sunday', '7_Sunday') if '0_Sunday' in x else x
)
Expand Down Expand Up @@ -1326,7 +1330,7 @@ def export_figure(
elif save and show:
plotly.offline.plot(fig, filename=str(filename))
elif save and not show:
fig.write_html(filename)
fig.write_html(str(filename))
return figure_like

elif isinstance(figure_like, tuple):
Expand Down
4 changes: 2 additions & 2 deletions flixopt/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class CalculationResults:
"""

@classmethod
def from_file(cls, folder: Union[str, pathlib.Path], name: str):
def from_file(cls, folder: Union[str, pathlib.Path], name: str) -> 'CalculationResults':
"""Create CalculationResults instance by loading from saved files.

This method loads the calculation results from previously saved files,
Expand Down Expand Up @@ -100,7 +100,7 @@ def from_file(cls, folder: Union[str, pathlib.Path], name: str):
)

@classmethod
def from_calculation(cls, calculation: 'Calculation'):
def from_calculation(cls, calculation: 'Calculation') -> 'CalculationResults':
"""Create CalculationResults directly from a Calculation object.

This method extracts the solution, flow system, and other relevant
Expand Down
30 changes: 16 additions & 14 deletions flixopt/solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class _Solver:
"""
Abstract base class for solvers.

Attributes:
mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
and the lower bound, which is the theoretically optimal solution (LP)
logfile_name (str): Filename for saving the solver log.
Args:
mip_gap: Acceptable relative optimality gap in [0.0, 1.0].
time_limit_seconds: Time limit in seconds.
extra_options: Additional solver options merged into `options`.
"""

name: ClassVar[str]
Expand All @@ -38,11 +38,12 @@ def _options(self) -> Dict[str, Any]:

class GurobiSolver(_Solver):
"""
Gurobi solver configuration.

Args:
mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
and the lower bound, which is the theoretically optimal solution (LP)
time_limit_seconds (int): Solver's time limit in seconds.
extra_options (str): Filename for saving the solver log.
mip_gap: Acceptable relative optimality gap in [0.0, 1.0]; mapped to Gurobi `MIPGap`.
time_limit_seconds: Time limit in seconds; mapped to Gurobi `TimeLimit`.
extra_options: Additional solver options merged into `options`.
"""

name: ClassVar[str] = 'gurobi'
Expand All @@ -57,12 +58,13 @@ def _options(self) -> Dict[str, Any]:

class HighsSolver(_Solver):
"""
Args:
mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
and the lower bound, which is the theoretically optimal solution (LP)
time_limit_seconds (int): Solver's time limit in seconds.
threads (int): Number of threads to use.
extra_options (str): Filename for saving the solver log.
HiGHS solver configuration.

Attributes:
mip_gap: Acceptable relative optimality gap in [0.0, 1.0]; mapped to HiGHS `mip_rel_gap`.
time_limit_seconds: Time limit in seconds; mapped to HiGHS `time_limit`.
extra_options: Additional solver options merged into `options`.
threads (Optional[int]): Number of threads to use. If None, HiGHS chooses.
"""

threads: Optional[int] = None
Expand Down
1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ plugins:
- include-markdown
- mike:
version_selector: true
default_version: latest
- gen-files:
scripts:
- scripts/gen_ref_pages.py
Expand Down
2 changes: 1 addition & 1 deletion scripts/gen_ref_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
index_file.write('# API Reference\n\n')
index_file.write(
'This section contains the documentation for all modules and classes in flixopt.\n'
'For more information on how to use the classes and functions, see the [Concepts & Math](../concepts-and-math/index.md) section.\n'
'For more information on how to use the classes and functions, see the [User Guide](../user-guide/index.md) section.\n'
)

with mkdocs_gen_files.open(f'{api_dir}/SUMMARY.md', 'w') as nav_file:
Expand Down