Skip to content
Open
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
162 changes: 131 additions & 31 deletions doc/4_Interoperability/3_hybrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,48 +43,147 @@ The following steps describe how to **link the GEMS part of the study to the Leg

### Abstract definition of the area-connection field type (in the [library](../3_User_Guide/3_GEMS_File_Structure/2_library.md) file)

In order to successfully inject a GEMS component’s port into an Antares Legacy Area, the port’s type must declare which field represents the power injection. This is configured in the [library](../3_User_Guide/3_GEMS_File_Structure/2_library.md) of the component's model (e.g., a file `model-libraries/library.yml`). Within the port type definition, an `area-connection` section specifies an `injection-field`. The `injection-field` designates which field of that port will be added to the connected area’s balance equation. For example, for a port type that carries power `flow`, it is defined in the library as follows:
In order to successfully inject a GEMS component’s port into an Antares Legacy Area, the port’s type must declare which field will contribute to the optimization problem. This is configured in the [library](../3_User_Guide/3_GEMS_File_Structure/2_library.md) of the component's model (e.g. a file `model-libraries/library.yml`).

The `area-connection` section is optional in general, but becomes mandatory when the port type is intended to be used in a **hybrid study**. It can accept 3 types of fields `injection-to-balance`, `spillage-bound` and `unsupplied-energy-bound` :

```yaml
port-types:
- id: flow
description: A port that transfers a power flow.
fields:
- id: flow
area-connection:
- injection-field: flow
port-types:
- id: port-to-area
fields:
- id: field_to_balance
- id: to-area-bound
- id: from-area-bound
area-connection:
injection-to-balance: field_to_balance
spillage-bound: to-area-bound
unsupplied-energy-bound: from-area-bound
```

The `area-connection` section is optional in general, but becomes mandatory when the port type is intended to be used in a **hybrid study**.
The nature of the contribution depends on the fields:

- `injection-to-balance`: the linear expression is injected in the balance constraint of the area.
- `spillage-bound`: the linear expression is added to the sum of all variables or linear expressions already used to bound the spillage in the constraint called "fictitious load".
- `unsupplied-energy-bound`: the linear expression is added to any linear expression already used to bound the unsupplied energy.

These fields are independent: you don't have to define all 3 at the same time, you can define only one. However, all three keys must be present in the `area-connection` section even if some values are left empty.

#### Single field case

It's not mandatory to connect one field for each `area-connection` entry, it's possible to define only one of them. For example, for a port type that carries power `flow_field` and only connects to the balance constraint, it is defined in the library as follows:

```yaml
port-types:
- id: flow_port
description: A port that transfers a power flow.
fields:
- id: flow_field
area-connection:
injection-to-balance: flow_field
spillage-bound:
unsupplied-energy-bound:

models:
- id: my-production
parameters:
- id: flat_production
ports:
- id: balance_port
type: flow_port
port-field-definitions:
- port: balance_port
field: flow_field
definition: flat_production
```

### Conventions on the sign of expressions

When connecting a component to an area, you must respect conventions on the sign of the linear expression contributed by the port field.

![Table representing the different sign conventions](../assets/4_sign_conventions.png)

<details>
<summary>Sign conventions for the <code>injection-to-balance</code></summary>

<ul>
<li>If you need to involve a <strong>production</strong>, make the expression <strong>positive</strong> (no <code>-</code> prefix):
<pre><code class="language-yaml">port-field-definitions:
- port: balance_port
field: flow_field
definition: flat_production # positive production
</code></pre>
</li>
<li>If you need to involve a <strong>load</strong>, make the expression <strong>negative</strong> (prefix with <code>-</code>):
<pre><code class="language-yaml">port-field-definitions:
- port: balance_port
field: flow_field
definition: -flat_load # negative load
</code></pre>
</li>
</ul>

</details>

<details>
<summary>Sign conventions for the <code>spillage-bound</code></summary>

<p>This connection is intended to limit the spillage optimization variable. The convention is the same as for the balance constraint: make the <strong>production positive</strong>, with no <code>-</code> prefix:</p>

<pre><code class="language-yaml">port-field-definitions:
- port: spillage_port
field: to-area-bound
definition: flat_production # positive production
</code></pre>

</details>

<details>
<summary>Sign conventions for the <code>unsupplied-energy-bound</code></summary>

The `injection-field` explicitly designates which field of the port contributes to the area balance equation in the legacy Antares Simulator study.
<p>This connection is intended to limit the unsupplied energy optimization variable. Here, make the <strong>load positive</strong>, with no <code>-</code> prefix:</p>

<pre><code class="language-yaml">port-field-definitions:
- port: unsup_energy_port
field: from-area-bound
definition: flat_load # positive load
</code></pre>

</details>

### Definition of the area-connections (in the [system](../3_User_Guide/3_GEMS_File_Structure/3_system.md) file)

The `area-connections` section of the system file is used to declare each connection between a GEMS component and an Antares Legacy Area.

For every component that should supply or interact with an Antares Area, an entry is added specifying the component, the port through which it connects, and the target area name. The port must support the area injection field type. For example, to connect a component `wind_farm` to a legacy area `area1` through `wind_farm`s port named `balance_port`, the following configuration is used:
For every component that should supply or interact with an Antares Area, an entry is added specifying the component, the port through which it connects, and the target area name. The port must belong to a port type that defines an `area-connection` section in the model library. For example, to connect a component `wind_farm` to a legacy area `area1` through `wind_farm`'s port named `balance_port`, the following configuration is used:

```yaml
area-connections:
- component: wind_farm
port: balance_port
area: area1
- component: wind_farm
port: balance_port
area: area1
```

Explanation of fields:

- **component:** Refers to the `id` of the GEMS component to be connected. This `id` must match the one declared in the components section of the `system.yml` file. In this example, it refers to a component named `wind_farm`
- **port:** Specifies which port on the component is used to establish the connection to the Antares Simulator area. The corresponding port type must include an `area-connection` section in the model library definition, and must specify an `injection-field` that will be used by the solver
- **area:** Indicates the target Antares Simulator area. The component's output, through the defined port, will contribute to this Antares Simulator area’s balance constraint during simulation.
- **port:** Specifies which port on the component is used to establish the connection to the Antares Simulator area. The corresponding **port type** must include an `area-connection` section in the model library definition, and must specify at least one of `injection-to-balance`, `spillage-bound` or `unsupplied-energy-bound`
- **area:** Indicates the target Antares Simulator area. The component's output, through the defined port, will contribute to this Antares Simulator area's balance constraint during simulation

## Outputs

The study will generate two types of output files:

- [**Files similar to Legacy studies**](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/03-outputs/): outputs corresponding to the optimization results coming from the components created by the Legacy study.
- [**Simulation tables**](https://antares-simulator.readthedocs.io/en/latest/user-guide/modeler/03-outputs/): specific to modeler's components optimization, in the same output folder as the Legacy outputs. One simulation table for each optimization step (called `simulation_table--optim-nb-X`) will be generated.


## How to run a hybrid study

After setting up the connections as described above, **running a hybrid study** is done in the same way as [running a standard Antares simulation](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/10-command-line/). The study can be opened or launched with Antares Simulator (using the GUI or the command-line solver). The presence of the file `system.yml` and the folder `model-libraries` in the input folder will trigger the Antares solver’s GEMS interpreter to load those components. The solver will then construct a combined optimization problem that includes both the Legacy elements (areas, thermal plants, hydro, etc.) and the GEMS components defined by the user.

Once the run starts, it will simulate with the combined model. Results for the GEMS components (e.g., generation output of a custom component) will appear alongside the usual Antares results for areas, provided that output has been configured for those components (the GEMS framework will handle output storage in the study results).

## Simple example of a hybrid study
## Simple example of a [hybrid study](https://github.com/AntaresSimulatorTeam/GEMS/tree/main/resources/Documentation_Examples/Hybrid_Study)

This section represents a simple example of a hybrid study that demonstrates how to integrate GEMS models into Antares Simulator. The example can be found in the [resources folder](https://github.com/AntaresSimulatorTeam/GEMS/tree/main/resources/Documentation_Examples) and covers a one-week time horizon.

Expand All @@ -104,26 +203,28 @@ library:
id: example_library

port-types:
- id: flow
- id: flow_port
description: A port that transfers a power flow.
fields:
- id: flow
- id: flow_field
area-connection:
- injection-field: flow
injection-to-balance: flow_field
spillage-bound:
unsupplied-energy-bound:

models:
- id: renewable
parameters:
- id: generation
time-dependent: true
scenario-dependent: true
- id: generation
time-dependent: true
scenario-dependent: true
ports:
- id: balance_port
type: flow
- id: balance_port
type: flow_port
port-field-definitions:
- port: balance_port
field: flow
definition: generation
- port: balance_port
field: flow_field
definition: generation
</code></pre>

<p><strong>system.yml :</strong></p>
Expand All @@ -133,7 +234,6 @@ system:
id: system

components:

- id: wind_farm
model: example_library.renewable
parameters:
Expand All @@ -160,11 +260,11 @@ In this specific case, wind generation during the first hour is 20MW and demand

When constructing hybrid studies, the following important constraints should be considered:

**Time Series Length**:
**Time Series Length:**

The time series data used in GEMS modeler components (for example, the generation profile of a renewable) must align with the Antares simulation horizon and resolution. In practice, this means the number of time steps and the granularity of GEMS time-dependent inputs should match the solver’s expectations (e.g., 8760 hourly values for a yearly hourly simulation). The hybrid solver will not accept a modeler time series that doesn’t fit the configured simulation timeframe.

**Integer/Binary Decision Variables**:
**Integer/Binary Decision Variables:**

If any GEMS component introduces integer or binary decision variables (for instance, a component that has an on/off state or unit commitment logic), Antares must be run in MILP mode. Antares Simulator’s solver has to be set to Mixed-Integer Linear Programming (the unit commitment MILP option) to handle discrete variables. In hybrid mode, the solver will incorporate those binary/integer variables into the optimization, but only if the MILP solver is enabled. If running with continuous (LP) mode while using components that require integer decisions, the simulation will not handle them correctly. Thus, the study’s optimization settings must be configured for MILP (unit commitment) when needed.
**Scenario dependency of Variables**:
Expand Down
10 changes: 5 additions & 5 deletions doc/assets/.$4_hybrid_study_scheme.drawio.bkp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.6 Chrome/140.0.7339.249 Electron/38.8.0 Safari/537.36" version="29.3.6">
<diagram name="Page-1" id="ksA6ywTk5pSFuDXFcJac">
<mxGraphModel dx="1956" dy="929" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<mxGraphModel dx="1663" dy="790" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
Expand All @@ -20,11 +20,11 @@
<mxCell id="4A_25u1ptR4q52VlzChD-4" parent="1" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;size=27;position=0.48;fillColor=#F0FDF4;strokeColor=#166534;strokeWidth=1;fontSize=12;fontStyle=1;fontColor=#166534;base=12;" value="GEMS" vertex="1">
<mxGeometry height="50" width="97" x="615.5" y="180" as="geometry" />
</mxCell>
<mxCell id="4A_25u1ptR4q52VlzChD-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#065F46;strokeColor=#064E3B;strokeWidth=2;fontColor=#FFFFFF;fontStyle=1;fontSize=13;" value="⚡ Wind_Farm&lt;div&gt;Variable Output&lt;/div&gt;" vertex="1">
<mxCell id="4A_25u1ptR4q52VlzChD-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#065F46;strokeColor=#064E3B;strokeWidth=2;fontColor=#FFFFFF;fontStyle=1;fontSize=13;" value="⚡ Wind_Farm&lt;div&gt;balance_port (Output)&lt;/div&gt;" vertex="1">
<mxGeometry height="70" width="150" x="589" y="242" as="geometry" />
</mxCell>
<mxCell id="4A_25u1ptR4q52VlzChD-6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#475569;strokeColor=#334155;strokeWidth=2;fontColor=#FFFFFF;fontStyle=1;fontSize=13;" value="&amp;nbsp;Area Connection /&amp;nbsp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));&quot;&gt;Port Settings&lt;/span&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;scriptor-paragraph&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="125.5" width="280" x="290" y="250" as="geometry" />
<mxCell id="4A_25u1ptR4q52VlzChD-6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#475569;strokeColor=#334155;strokeWidth=2;fontColor=#FFFFFF;fontStyle=1;fontSize=13;" value="Area Connection /&amp;nbsp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));&quot;&gt;Port Settings&lt;/span&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;scriptor-paragraph&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="125.5" width="280" x="270" y="214.25" as="geometry" />
</mxCell>
<mxCell id="4A_25u1ptR4q52VlzChD-7" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#3B82F6;strokeColor=#1E40AF;strokeWidth=2;fontColor=#FFFFFF;fontStyle=1;fontSize=13;" value="💡 Load&lt;br&gt;&lt;div&gt;60 MW&lt;br&gt;&lt;i&gt;(constant)&lt;/i&gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="70" width="150" x="71" y="134" as="geometry" />
Expand All @@ -43,7 +43,7 @@
</mxGeometry>
</mxCell>
<mxCell id="z1juipBl3MY95k2tCydu-1" parent="1" style="rounded=4;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#cccccc;strokeWidth=1;fontFamily=Courier New;fontSize=13;align=left;fontColor=#333333;" value="&lt;div style=&quot;font-size: 13px; font-family: Courier New; text-align: left;&quot;&gt;&lt;b&gt;area-connections:&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;font-size: 13px; font-family: Courier New; text-align: left;&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp; - component: wind_farm&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;font-size: 13px; font-family: Courier New; text-align: left;&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; port: balance_port&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;font-size: 13px; font-family: Courier New; text-align: left;&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; area: Area&lt;/b&gt;&lt;/div&gt;" vertex="1">
<mxGeometry height="80" width="190" x="335" y="290" as="geometry" />
<mxGeometry height="80" width="205.62" x="307.19" y="250" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
Expand Down
Binary file added doc/assets/.$4_hybrid_study_scheme.png.bkp
Binary file not shown.
Loading
Loading