diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index f4b497ab..d09b0f3e 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -8,47 +8,50 @@ on: jobs: test: runs-on: ubuntu-22.04 - + steps: - name: Checkout repository uses: actions/checkout@v4 - + - name: Set up Python 3.11 uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' - + - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - - - name: Download Antares v9.3.2 release + + - name: Download Antares release run: | - echo "Downloading Antares v9.3.2..." - curl -L -f -o antares-9.3.2-Ubuntu-22.04.tar.gz \ - https://github.com/AntaresSimulatorTeam/Antares_Simulator/releases/download/v9.3.2/antares-9.3.2-Ubuntu-22.04.tar.gz - - if [ ! -f "antares-9.3.2-Ubuntu-22.04.tar.gz" ]; then + source versions/antares-simulator.txt + echo "Downloading Antares v${ANTARES_SIMULATOR_VERSION}..." + curl -L -f -o antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz \ + https://github.com/AntaresSimulatorTeam/Antares_Simulator/releases/download/v${ANTARES_SIMULATOR_VERSION}/antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz + + if [ ! -f "antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz" ]; then echo "Error: Download failed" exit 1 fi - - echo "Download successful. File size: $(ls -lh antares-9.3.2-Ubuntu-22.04.tar.gz | awk '{print $5}')" - + + echo "Download successful. File size: $(ls -lh antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz | awk '{print $5}')" + - name: Extract Antares binaries run: | + source versions/antares-simulator.txt echo "Extracting archive..." - tar -xzf antares-9.3.2-Ubuntu-22.04.tar.gz - + tar -xzf antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz --strip-components=1 --one-top-level=antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04 + - name: Run end-to-end tests run: | python -m pytest tests/e2e_tests -v - + - name: Cleanup if: always() run: | - rm -f antares-9.3.2-Ubuntu-22.04.tar.gz - rm -rf antares-9.3.2-Ubuntu-22.04 - echo "Cleanup completed" \ No newline at end of file + source versions/antares-simulator.txt + rm -f antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04.tar.gz + rm -rf antares-${ANTARES_SIMULATOR_VERSION}-Ubuntu-22.04 + echo "Cleanup completed" diff --git a/doc/0_Home/2_core_concepts.md b/doc/0_Home/2_core_concepts.md index f4d44c57..8e31c769 100644 --- a/doc/0_Home/2_core_concepts.md +++ b/doc/0_Home/2_core_concepts.md @@ -1,3 +1,7 @@ +--- +description: Explore GEMS key design principles — graph-based algebraic modelling, solver-independent syntax, YAML-based configuration, and support for LP, MIP, and MILP energy optimisation problems. +--- +
GEMS Logo @@ -16,6 +20,119 @@ This language **differs from traditional optimization languages** in several way
+# Defining Models and Systems as YAML Configurations + +
+
+ +

Library

+ +A YAML file defining abstract objects called
models, which describe the mathematical formulation of a category of energy system element. + +
+
+For more details, see the Library page of the user guide. + +```yaml +library: + + id: example_library + description: "Example model library" + + models: + - id: bus + description: "A simple balance node model" + ports: + - id: balance_port + type: flow_port + binding-constraints: + - id: balance + expression: sum_connections(flow_port.flow) = 0 + + - id: generator + parameters: + - id: p_min + - id: p_max + - id: generation_cost + - id: co2_emission_factor + variables: + - id: generation + lower-bound: p_min + upper-bound: p_max + variable-type: continuous + ports: + - id: balance_port + type: flow + - id: energy_port + type: energy + - id: emission_port + type: emission + port-field-definitions: + - port: balance_port + field: flow + definition: generation + - port: energy_port + field: cumulative_energy + definition: sum(generation) + - port: emission_port + field: co2 + definition: sum(generation * co2_emission_factor) + objective-contributions: + - id: objective + expression: sum(generation_cost * generation) +``` + +
+
+ +

System

+ +A YAML file describing the concrete energy system to be simulated. It instantiates components from models provided by the libraries, assigns parameter values, and defines the connections between components. + +
+For more details, see the System page of the user guide. + +```yaml +system: + id: my_system + description: "An example system with one load, one node, one thermal generator" + model-libraries: example_library + components: + + - id: load_1 + model: example_library.load + scenario-group: load_group + parameters: + - id: load + time-dependent: true + value: demand_profile + + - id: bus_1 + model: example_library.bus + parameters: + - id: spillage_cost + value: 1000 + - id: unsupplied_energy_cost + value: 10000 + + - id: generator_1 + model: example_library.generator + parameters: + - id: p_min + value: 70 + - id: p_max + value: 100 + - id: generation_cost + value: 35 + - id: co2_emission_factor + value: 10 +``` + +
+
+ # Key Design Principles and Capabilities ## Separating Model Definition from Solver Execution diff --git a/doc/0_Home/3_use_cases.md b/doc/0_Home/3_use_cases.md index b04b02e9..82ed6f70 100644 --- a/doc/0_Home/3_use_cases.md +++ b/doc/0_Home/3_use_cases.md @@ -1,3 +1,7 @@ +--- +description: Discover the main use cases of GEMS — adequacy assessment, economic dispatch, energy system planning, multi-energy modelling, and hybrid integration with Antares Simulator. +--- +
GEMS Logo diff --git a/doc/0_Home/4_release_notes.md b/doc/0_Home/4_release_notes.md index 07daad32..6a67732b 100644 --- a/doc/0_Home/4_release_notes.md +++ b/doc/0_Home/4_release_notes.md @@ -6,18 +6,29 @@ # Release Notes -## Version 0.2.0 +## v0.3.0 | *22-04-2026* -**Release Date:** *26/03/2026* +### Added +* Add the raw YAML files in the Overview section ([PR36](https://github.com/AntaresSimulatorTeam/GEMS/pull/93)) +* Add GitHub Action for automatically verifying the latest released antares-simulator version ([PR36-bis](https://github.com/AntaresSimulatorTeam/GEMS/pull/85)) -* Update the appearance of the documentation ([PR32](https://github.com/AntaresSimulatorTeam/GEMS/pull/66)) -* Clarify the distinction between Antares Modeler and Antares Solver ([PR32](https://github.com/AntaresSimulatorTeam/GEMS/pull/66)) -* Dynamic visualization of libraries ([PR31](https://github.com/AntaresSimulatorTeam/GEMS/pull/63)) +### Changed +* Upgrade SEO ([PR38](https://github.com/AntaresSimulatorTeam/GEMS/pull/97)) +* Use the newest version of Antares-Legacy-Models Library for Quick Start Example 2 ([PR35](https://github.com/AntaresSimulatorTeam/GEMS/pull/86)) +* Update the documentation area-connection part in Hybrid Studies ([PR34](https://github.com/AntaresSimulatorTeam/GEMS/pull/84)) + +## v0.2.0 | *26-03-2026* + +### Added * Document floor, ceil, max, min operators ([PR30](https://github.com/AntaresSimulatorTeam/GEMS/pull/62)) +* Dynamic visualization of libraries ([PR31](https://github.com/AntaresSimulatorTeam/GEMS/pull/63)) +### Changed +* Update the appearance of the documentation ([PR32](https://github.com/AntaresSimulatorTeam/GEMS/pull/66)) +* Clarify the distinction between Antares Modeler and Antares Solver ([PR32](https://github.com/AntaresSimulatorTeam/GEMS/pull/66)) -## Version 0.1.0 -**Release Date:** *22/01/2026* +## v0.1.0 | *22-01-2026* +### Added * Initialization of the documentation \ No newline at end of file diff --git a/doc/1_Overview/1_Architecture.md b/doc/1_Overview/1_Architecture.md index eb4d2940..c354148a 100644 --- a/doc/1_Overview/1_Architecture.md +++ b/doc/1_Overview/1_Architecture.md @@ -1,3 +1,7 @@ +--- +description: Learn how GEMS architecture differs from classical OOME architectures by externalising model definitions into YAML files, enabling solver-agnostic and reusable energy system models. +--- +
GEMS Logo diff --git a/doc/1_Overview/2_glossary.md b/doc/1_Overview/2_glossary.md index 1004968e..b44e3749 100644 --- a/doc/1_Overview/2_glossary.md +++ b/doc/1_Overview/2_glossary.md @@ -1,3 +1,7 @@ +--- +description: GEMS glossary — definitions of core concepts including libraries, models, components, ports, connections, system files, and data series used in the GEMS framework. +--- +
GEMS Logo diff --git a/doc/2_Getting_Started/1A_modeler_installation.md b/doc/2_Getting_Started/1A_modeler_installation.md index a42547b1..fd44232e 100644 --- a/doc/2_Getting_Started/1A_modeler_installation.md +++ b/doc/2_Getting_Started/1A_modeler_installation.md @@ -1,3 +1,7 @@ +--- +description: Step-by-step installation guide for Antares Simulator's GEMS interpreter (Antares Modeler) — download, extract, and configure the GEMS interpreter within Antares Simulator. +--- +
GEMS Logo @@ -81,7 +85,7 @@ Let’s check if Modeler is working correctly. - Use the Hybrid Study tutorial : - Refer to the tutorial inside the [Interoperability — Antares Hybrid Mode](../4_Interoperability/3_hybrid.md) section + Refer to the tutorial inside the [Interoperability — Antares Hybrid Mode](../4_Interoperability/3_hybrid/1_overview.md) section - Run the following commands : ```bash diff --git a/doc/2_Getting_Started/2B_QSE_unit_commitment.md b/doc/2_Getting_Started/2B_QSE_unit_commitment.md index 378b99ea..e883c30b 100644 --- a/doc/2_Getting_Started/2B_QSE_unit_commitment.md +++ b/doc/2_Getting_Started/2B_QSE_unit_commitment.md @@ -12,6 +12,11 @@ This tutorial demonstrates a simple example of a **unit commitment** problem sta The study folder is on the [GEMS Github repository](https://github.com/AntaresSimulatorTeam/GEMS/tree/main/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment). + + ### Files Structure The diagram below describe the file structure of the [study](https://github.com/AntaresSimulatorTeam/GEMS/tree/main/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment). diff --git a/doc/3_User_Guide/1_introduction.md b/doc/3_User_Guide/1_introduction.md index a0425a0e..311cc916 100644 --- a/doc/3_User_Guide/1_introduction.md +++ b/doc/3_User_Guide/1_introduction.md @@ -1,3 +1,7 @@ +--- +description: Introduction to the GEMS framework — how to describe energy systems declaratively using structured YAML files, mathematical expressions, and graph-based component connections. +--- +
GEMS Logo @@ -27,8 +31,6 @@ From a documentation perspective, the User Guide is organized into **four comple This separation is fundamental to understanding how [GEMS](../index.md) systems are written, interpreted, validated, and analysed. ---- - ## Mathematical Syntax The **GEMS Framework Mathematical Syntax** represents set of rules for creating mathematical expressions which will be used in building an optimization problem. @@ -48,8 +50,6 @@ Mathematical syntax focuses exclusively on *equations and rules*. It does not de See: [**Mathematical Syntax and Rules**](./2_mathematical_syntax.md) ---- - ## File Structure The **GEMS Framework File Structure** defines how components are **declared, structured, and connected** to form a system, and how these systems can be translated as optimization problems, using YAML files. diff --git a/doc/3_User_Guide/2_mathematical_syntax.md b/doc/3_User_Guide/2_mathematical_syntax.md index d2fde095..5787c011 100644 --- a/doc/3_User_Guide/2_mathematical_syntax.md +++ b/doc/3_User_Guide/2_mathematical_syntax.md @@ -1,3 +1,7 @@ +--- +description: Reference for GEMS mathematical expression syntax — operators, variables, parameters, port fields, linearity conditions, and time and scenario indexing mechanisms. +--- +
GEMS Logo @@ -100,11 +104,11 @@ If a variable is time-dependent (or scenario-dependent), it can only be used in ## Ports -Ports are the mechanism by which models exchange linear expressions. A port has one or more fields with each field carrying a linear expression. **Mathematical Expression Syntax** allows users to reference port fields in expressions using the notation `port_id.field_id`. This is essentially a way to use linear expressions coming from other connected models. +Ports are the mechanism by which models exchange mathematical expressions. A port has one or more fields with each field carrying an expression. **Mathematical Expression Syntax** allows users to reference port fields in expressions using the notation `port_id.field_id`. This is essentially a way to use expressions coming from other connected models. -When using a port field in an expression, the same dependency rules apply: if linear expressions of a port varies by time or scenario (which is deduced from how it’s defined – typically depending on time-dependent variables or parameters), then it can only be used in time-dependent or scenario-dependent constraints respectively. +When using a port field in an expression, the same dependency rules apply: if the expression of a port varies by time or scenario (which is deduced from how it’s defined – typically depending on time-dependent variables or parameters), then it can only be used in time-dependent or scenario-dependent constraints respectively. -If a port’s linear expressions need to be used in a time-independent manner (for example, when calculating a sum over the full time horizon), an aggregator must be applied to remove the time index. See the section on the [**Time Summation Operator**](#time-summation-full-horizon-sumx) for details. A practical implementation is provided in [`basic_models_library.yml`](https://github.com/AntaresSimulatorTeam/GEMS/blob/main/libraries/basic_models_library.yml) where the `emmision_port` is used to support pollutant-related constraints. +If a port’s expressions need to be used in a time-independent manner (for example, when calculating a sum over the full time horizon), an aggregator must be applied to remove the time index. See the section on the [**Time Summation Operator**](#time-summation-full-horizon-sumx) for details. A practical implementation is provided in [`basic_models_library.yml`](https://github.com/AntaresSimulatorTeam/GEMS/blob/main/libraries/basic_models_library.yml) where the `emission_port` is used to support pollutant-related constraints. ### Port Operator diff --git a/doc/4_Interoperability/1_PyPSA_to_GEMS_converter/1_overview.md b/doc/4_Interoperability/1_PyPSA_to_GEMS_converter/1_overview.md index 11bbc723..c39b9dba 100644 --- a/doc/4_Interoperability/1_PyPSA_to_GEMS_converter/1_overview.md +++ b/doc/4_Interoperability/1_PyPSA_to_GEMS_converter/1_overview.md @@ -1,3 +1,7 @@ +--- +description: Overview of the PyPSA-to-GEMS Converter — an open-source Python package that exports PyPSA networks as GEMS study folders, supporting linear OPF and stochastic optimisation. +--- +
GEMS Logo diff --git a/doc/4_Interoperability/2_antares_legacy.md b/doc/4_Interoperability/2_antares_legacy.md deleted file mode 100644 index 47c4bca2..00000000 --- a/doc/4_Interoperability/2_antares_legacy.md +++ /dev/null @@ -1,51 +0,0 @@ -![Template Banner](../assets/template_banner.svg) - - - -# Title 1 - - -## Sub-Title 2 -Content or text here. - -**Code block example (YAML):** -```yaml -connections: - - component1: generator1 - port1: injection_port - component2: node1 - port2: injection_port - - component1: generator2 - port1: injection_port - component2: node1 - port2: injection_port - - component1: demand - port1: injection_port - component2: node1 - port2: injection_port -``` - -**Code block example (Python):** -```python -print("Hello World") -``` -**Note Example:** - -
-🖊️ Note : This is an important note -
- - -**Simple Equation example:** - - $3 * parameter_1 * variable_a + variable_b + 56.4 <= variable_4 * 439$ - -**LATEC equation example:** -$$ -3 \cdot \text{parameter\_1} \cdot \text{variable\_a} + \text{variable\_b} + 56.4 \leq \text{variable\_4} \cdot 439 -$$ - diff --git a/doc/4_Interoperability/3_hybrid.md b/doc/4_Interoperability/3_hybrid.md deleted file mode 100644 index 942adace..00000000 --- a/doc/4_Interoperability/3_hybrid.md +++ /dev/null @@ -1,171 +0,0 @@ - - -# Antares Simulator Hybrid studies - -This page explains how to configure and run a [**hybrid study**](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/08-hybrid-studies/) i.e. a study combining **GEMS components** and **Antares Simulator's Legacy Components**. In a hybrid study, the GEMS files are integrated into a Antares Simulator study’s directory structure, allowing Antares Simulator to incorporate GEMS components. - -## Definition - -A [**hybrid study**](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/08-hybrid-studies/) is essentially a **Antares Simulator** study that includes additional **GEMS** input data (in the `input/` folder). The Antares Simulator executable (*antares-solver*) is able to run such a simulation, although the input directory contains **GEMS-specific files** (such as system, model libraries and data-series) describing GEMS components. - -In this hybrid mode, the file `parameter.yml` is not used: if it exists, it will be ignored. Instead, the study relies on the Antares Simulator simulation settings. In summary, the **hybrid study’s** input directory merges the modeler files with the typical Antares files, and the Antares solver’s built-in GEMS interpreter handles the GEMS components during the simulation. - -```text -Antares-Simulator-Study/ -├── input/ -│ ├── areas/ -│ ├── bindingconstraints/ -│ ├── ... -│ ├── model-libraries/ # Modeler libraries folder -│ ├── system.yml # Modeler system file -│ └── data-series/ # Modeler dataseries folder -├── layers/ -├── logs/ -├── output/ -├── settings/ -├── user/ -├── Desktop.ini -├── Logs.log -└── study.antares -``` - -## Hybrid connections: coupling GEMS Components with Legacy Areas - -In a **hybrid study**, a `area-connection` between a GEMS component and a Legacy Area means that the component contributes to the energy balance at the given node, through a given port (field). - -In practical terms, connecting a GEMS **Generator** component to an Antares Legacy Area injects the generator’s power output into that area’s balance equation (the supply-demand constraint). *Without this connection, the GEMS component would remain isolated*. - -The following steps describe how to **link the GEMS part of the study to the Legacy part**: - -### 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: - -```yaml - port-types: - - id: flow - description: A port that transfers a power flow. - fields: - - id: flow - area-connection: - - injection-field: flow -``` - -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 `injection-field` explicitly designates which field of the port contributes to the area balance equation in the legacy Antares Simulator study. - -### 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: - -```yaml -area-connections: - - 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. - -## 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 - -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. - -![Hybrid Study Scheme](../assets/4_hybrid_study_scheme.png) - -
-Hybrid Study Example Details - -

This consists of an area from Solver framework with a constant demand of 60 MW throughout one week and a wind farm component made from the renewable model from the basic-models-library.

- -

Concerning the connection between the area and the renewable component, it's configured by these yaml files:

- -

library.yml :

- -

-library:
-  id: example_library
-
-  port-types:
-    - id: flow
-      description: A port that transfers a power flow.
-      fields:
-      - id: flow
-      area-connection:
-      - injection-field: flow
-
-  models:
-    - id: renewable
-      parameters:
-      - id: generation
-        time-dependent: true
-        scenario-dependent: true
-      ports:
-      - id: balance_port
-        type: flow
-      port-field-definitions:
-      - port: balance_port
-        field: flow
-        definition: generation
-
- -

system.yml :

- -

-system:
-  id: system
-
-  components:
-
-    - id: wind_farm
-      model: example_library.renewable
-      parameters:
-        - id: generation
-          time-dependent: true
-          scenario-dependent: true
-          value: wind
-
-  area-connections:
-    - component: wind_farm
-      port: balance_port
-      area: Area
-
- -
- -Since the wind farm does not produce enough energy to fully cover the demand, the results include **Energy Not Served (ENS)**. - -This example is intended solely to demonstrate how the **GEMS component**, when connected to an **Antares Simulator area**, emits a linear expression that is incorporated into the area’s balance constraint. - -In this specific case, wind generation during the first hour is 20MW and demand is 60MW. As a result, the Antares area reports an ENS of 40MW, which is consistent with the balance shown in the simulation results. - -## Limitations - -When constructing hybrid studies, the following important constraints should be considered: - -**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**: - -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**: -In Antares Simulator Legacy mode, each MC scenario is optimized separately. Thus, hybrid studies cannot contain scenario-independent variables. If you try to use such a variable in hybrid mode, the solver will fail. \ No newline at end of file diff --git a/doc/4_Interoperability/3_hybrid/1_overview.md b/doc/4_Interoperability/3_hybrid/1_overview.md new file mode 100644 index 00000000..7fd484d0 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/1_overview.md @@ -0,0 +1,42 @@ + + +# Antares Simulator Hybrid studies + +This page explains how to configure and run a [**hybrid study**](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/08-hybrid-studies/) i.e. a study combining **GEMS components** and **Antares Simulator's Legacy Components**. In a hybrid study, the GEMS files are integrated into a Antares Simulator study's directory structure, allowing Antares Simulator to incorporate GEMS components. + +## Definition + +A [**hybrid study**](https://antares-simulator.readthedocs.io/en/latest/user-guide/solver/08-hybrid-studies/) is essentially a **Antares Simulator** study that includes additional **GEMS** input data (in the `input/` folder). The Antares Simulator executable (*antares-solver*) is able to run such a simulation, although the input directory contains **GEMS-specific files** (such as system, model libraries and data-series) describing GEMS components. + +In this hybrid mode, the file `parameter.yml` is not used: if it exists, it will be ignored. Instead, the study relies on the Antares Simulator simulation settings. In summary, the **hybrid study's** input directory merges the modeler files with the typical Antares files, and the Antares solver's built-in GEMS interpreter handles the GEMS components during the simulation. + +```text +Antares-Simulator-Study/ +├── input/ +│ ├── areas/ +│ ├── bindingconstraints/ +│ ├── ... +│ ├── model-libraries/ # Modeler libraries folder +│ ├── system.yml # Modeler system file +│ └── data-series/ # Modeler dataseries folder +├── layers/ +├── logs/ +├── output/ +├── settings/ +├── user/ +├── Desktop.ini +├── Logs.log +└── study.antares +``` + +## Table of Contents + +- [Coupling GEMS Components with Legacy Areas](2_hybrid_connections.md) +- [Run a Hybrid Study](4_how_to_run.md) +- [Outputs](3_outputs.md) +- [Simple Example](5_example.md) +- [Limitations](6_limitations.md) diff --git a/doc/4_Interoperability/3_hybrid/2_hybrid_connections.md b/doc/4_Interoperability/3_hybrid/2_hybrid_connections.md new file mode 100644 index 00000000..fdf58bc4 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/2_hybrid_connections.md @@ -0,0 +1,119 @@ + + +# Coupling GEMS Components with Legacy Areas + +In a **hybrid study**, a `area-connection` between a GEMS component and a Legacy Area means that the component contributes to the energy balance at the given node, through a given port (field). + +In practical terms, connecting a GEMS **Generator** component to an Antares Legacy Area injects the generator's power output into that area's balance equation (the supply-demand constraint). *Without this connection, the GEMS component would remain isolated*. + +The following steps describe how to **link the GEMS part of the study to the Legacy part**: + +## 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 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: 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 nature of the contribution depends on the fields: + +- `injection-to-balance`: the linear expression is injected in the balance constraint of the Legacy 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" in the Legacy Area. +- `unsupplied-energy-bound`: the linear expression is added to any linear expression already used to bound the unsupplied energy in the Legacy Area. + +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. + +## 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. + + +| Area Connecton Field | Sign Convention: Positive for... | +|---|---| +| injection-to-balance | Production | +| spillage-bound | Production | +| unsupplied-energy-bound | Load | + + +
+Sign conventions for the injection-to-balance + +
    +
  • If you need to involve a production, make the expression positive (no - prefix): +
    port-field-definitions:
    +  - port: balance_port
    +    field: flow_field
    +    definition: flat_production   # positive production
    +
    +
  • +
  • If you need to involve a load, make the expression negative (prefix with -): +
    port-field-definitions:
    +  - port: balance_port
    +    field: flow_field
    +    definition: -flat_load   # negative load
    +
    +
  • +
+ +
+ +
+Sign conventions for the spillage-bound + +

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

+ +
port-field-definitions:
+  - port: spillage_port
+    field: to-area-bound
+    definition: flat_production   # positive production
+
+ +
+ +
+Sign conventions for the unsupplied-energy-bound + +

This connection is intended to limit the unsupplied energy optimization variable. Here, make the load positive, with no - prefix:

+ +
port-field-definitions:
+  - port: unsup_energy_port
+    field: from-area-bound
+    definition: flat_load   # positive load
+
+ +
+ +## 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 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 +``` + +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 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 diff --git a/doc/4_Interoperability/3_hybrid/3_outputs.md b/doc/4_Interoperability/3_hybrid/3_outputs.md new file mode 100644 index 00000000..a49dd851 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/3_outputs.md @@ -0,0 +1,12 @@ + + +# 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. diff --git a/doc/4_Interoperability/3_hybrid/4_how_to_run.md b/doc/4_Interoperability/3_hybrid/4_how_to_run.md new file mode 100644 index 00000000..32215bc2 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/4_how_to_run.md @@ -0,0 +1,11 @@ + + +# 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). diff --git a/doc/4_Interoperability/3_hybrid/5_example.md b/doc/4_Interoperability/3_hybrid/5_example.md new file mode 100644 index 00000000..2b2939a7 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/5_example.md @@ -0,0 +1,78 @@ + + +# 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. + +![Hybrid Study Scheme](../../assets/4_hybrid_study_scheme.png) + +
+Hybrid Study Example Details + +

This consists of an area from Solver framework with a constant demand of 60 MW throughout one week and a wind farm component made from the renewable model from the basic-models-library.

+ +

Concerning the connection between the area and the renewable component, it's configured by these yaml files:

+ +

library.yml :

+ +

+library:
+  id: example_library
+
+  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: renewable
+      parameters:
+        - id: generation
+          time-dependent: true
+          scenario-dependent: true
+      ports:
+        - id: balance_port
+          type: flow_port
+      port-field-definitions:
+        - port: balance_port
+          field: flow_field
+          definition: generation
+
+ +

system.yml :

+ +

+system:
+  id: system
+
+  components:
+    - id: wind_farm
+      model: example_library.renewable
+      parameters:
+        - id: generation
+          time-dependent: true
+          scenario-dependent: true
+          value: wind
+
+  area-connections:
+    - component: wind_farm
+      port: balance_port
+      area: Area
+
+ +
+ +Since the wind farm does not produce enough energy to fully cover the demand, the results include **Energy Not Served (ENS)**. + +This example is intended solely to demonstrate how the **GEMS component**, when connected to an **Antares Simulator area**, emits a linear expression that is incorporated into the area's balance constraint. + +In this specific case, wind generation during the first hour is 20MW and demand is 60MW. As a result, the Antares area reports an ENS of 40MW, which is consistent with the balance shown in the simulation results. diff --git a/doc/4_Interoperability/3_hybrid/6_limitations.md b/doc/4_Interoperability/3_hybrid/6_limitations.md new file mode 100644 index 00000000..b4e28c23 --- /dev/null +++ b/doc/4_Interoperability/3_hybrid/6_limitations.md @@ -0,0 +1,20 @@ + + +# Limitations + +When constructing hybrid studies, the following important constraints should be considered: + +**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:** + +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**: +In Antares Simulator Legacy mode, each MC scenario is optimized separately. Thus, hybrid studies cannot contain scenario-independent variables. If you try to use such a variable in hybrid mode, the solver will fail. diff --git a/doc/5_Examples/2_optimization_problem.md b/doc/5_Examples/2_optimization_problem.md deleted file mode 100644 index 47c4bca2..00000000 --- a/doc/5_Examples/2_optimization_problem.md +++ /dev/null @@ -1,51 +0,0 @@ -![Template Banner](../assets/template_banner.svg) - - - -# Title 1 - - -## Sub-Title 2 -Content or text here. - -**Code block example (YAML):** -```yaml -connections: - - component1: generator1 - port1: injection_port - component2: node1 - port2: injection_port - - component1: generator2 - port1: injection_port - component2: node1 - port2: injection_port - - component1: demand - port1: injection_port - component2: node1 - port2: injection_port -``` - -**Code block example (Python):** -```python -print("Hello World") -``` -**Note Example:** - -
-🖊️ Note : This is an important note -
- - -**Simple Equation example:** - - $3 * parameter_1 * variable_a + variable_b + 56.4 <= variable_4 * 439$ - -**LATEC equation example:** -$$ -3 \cdot \text{parameter\_1} \cdot \text{variable\_a} + \text{variable\_b} + 56.4 \leq \text{variable\_4} \cdot 439 -$$ - diff --git a/doc/5_Examples/3_hybrid.md b/doc/5_Examples/3_hybrid.md deleted file mode 100644 index 47c4bca2..00000000 --- a/doc/5_Examples/3_hybrid.md +++ /dev/null @@ -1,51 +0,0 @@ -![Template Banner](../assets/template_banner.svg) - - - -# Title 1 - - -## Sub-Title 2 -Content or text here. - -**Code block example (YAML):** -```yaml -connections: - - component1: generator1 - port1: injection_port - component2: node1 - port2: injection_port - - component1: generator2 - port1: injection_port - component2: node1 - port2: injection_port - - component1: demand - port1: injection_port - component2: node1 - port2: injection_port -``` - -**Code block example (Python):** -```python -print("Hello World") -``` -**Note Example:** - -
-🖊️ Note : This is an important note -
- - -**Simple Equation example:** - - $3 * parameter_1 * variable_a + variable_b + 56.4 <= variable_4 * 439$ - -**LATEC equation example:** -$$ -3 \cdot \text{parameter\_1} \cdot \text{variable\_a} + \text{variable\_b} + 56.4 \leq \text{variable\_4} \cdot 439 -$$ - diff --git a/doc/6_Support_Contributing/1_faq.md b/doc/6_Support_Contributing/1_faq.md index cbf2f4e2..fd8d761e 100644 --- a/doc/6_Support_Contributing/1_faq.md +++ b/doc/6_Support_Contributing/1_faq.md @@ -14,7 +14,7 @@ Currently, there is no GUI integrated into the [Antares Simulator repository](ht ### Can I use GEMS components inside a Legacy Study ? -Yes, you can run hybrid studies (a Legacy study with GEMS components inside) with Antares Legacy. For a pratical tutorial, refer to the [Hybrid Study Section](../4_Interoperability/3_hybrid.md). +Yes, you can run hybrid studies (a Legacy study with GEMS components inside) with Antares Legacy. For a pratical tutorial, refer to the [Hybrid Study Section](../4_Interoperability/3_hybrid/1_overview.md). ### Can I model unit commitment with GEMS? diff --git a/doc/6_Support_Contributing/3_contributing.md b/doc/6_Support_Contributing/3_contributing.md index 9dbeaea1..cb13fca6 100644 --- a/doc/6_Support_Contributing/3_contributing.md +++ b/doc/6_Support_Contributing/3_contributing.md @@ -1,3 +1,7 @@ +--- +description: How to contribute to GEMS — guidelines for code contributions, documentation improvements, and model library contributions to the GEMS open-source project. +--- +
GEMS Logo diff --git a/doc/6_Support_Contributing/4_pr_management.md b/doc/6_Support_Contributing/4_pr_management.md new file mode 100644 index 00000000..32096047 --- /dev/null +++ b/doc/6_Support_Contributing/4_pr_management.md @@ -0,0 +1,411 @@ +# GEMS Ecosystem — Developer Guidelines + +This document defines the **standard development, branching, versioning, CI/CD, and release workflow** across all official GEMS ecosystem repositories. + +--- + +## Repositories in Scope + +| Repository | Purpose | +|---|---| +| [GEMS](https://github.com/AntaresSimulatorTeam/GEMS) | Language specification, model libraries, documentation | +| [AntaresLegacyModels-to-GEMS-Converter](https://github.com/AntaresSimulatorTeam/AntaresLegacyModels-to-GEMS-Converter) | Converts Antares legacy studies to GEMS format | +| [PyPSA-to-GEMS-Converter](https://github.com/AntaresSimulatorTeam/PyPSA-to-GEMS-Converter) | Converts PyPSA networks to GEMS studies | + +--- + +## 1. Starting a Change + +Every change **must start from a tracked GitHub Issue** in the relevant repository. + +The issue must describe: + +- purpose of the change +- compatibility impact +- applicable process ID (see Section 3) + +PRs without an associated issue are only allowed for trivial documentation fixes or emergency hotfixes. + +--- + +## 2. Branch Management + +### Core Branches + +| Branch | Role | +|---|---| +| `main` | Production state. Every commit is a tagged release. | +| `develop` | Integration branch for the next release. Updated via PRs only. | + +Direct commits to `main` or `develop` are **not allowed**. + +### Working Branch Types + +| Type | Purpose | +|---|---| +| `feature/...` | New functionality | +| `bugfix/...` | Bug fixes | +| `refactor/...` | Internal restructuring | +| `perf/...` | Performance improvements | +| `docs/...` | Documentation changes | +| `chore/...` | Maintenance, dependency updates | +| `release/vX.Y.Z` | Release preparation | +| `hotfix/vX.Y.Z` | Urgent post-release corrections | + +### Naming Convention + +``` +/ + +feature/add-sts-model +bugfix/fix-thermal-parameter-mapping +chore/update-antares-craft-dependency +``` + +All branches are created from `develop`, except hotfixes which branch from `main`. + +--- + +## 3. Process IDs and Issue Templates + +Each repository defines named governance processes. When opening an issue, select the applicable process template. + +### GEMS + +| Process | Trigger | Template | +|---|---|---| +| **DOC-01** | New Antares-Simulator release affecting the GEMS Language definition | `doc-01.yml` | +| **DOC-02** | Internal documentation improvement | `doc-02.yml` | +| **LT-01** | New Antares-Simulator release affecting model libraries or taxonomies | `lt-01.yml` | +| **LT-02** | Internal library or taxonomy bug fix or improvement | `lt-02.yml` | +| **LT-03** | New model library or taxonomy | `lt-03.yml` | + +Incoming cross-repo notifications from the converters are handled under **LT-02**. + +### PyPSA-to-GEMS-Converter + +| Process | Trigger | Template | +|---|---|---| +| **P2G-01** | New Antares-Simulator release | `p2g-01.yml` | +| **P2G-02** | Internal change or model library update | `p2g-02.yml` | +| **P2G-03** | New PyPSA release | `p2g-03.yml` | + +### AntaresLegacyModels-to-GEMS-Converter + +| Process | Trigger | Template | +|---|---|---| +| **A2G-01** | New Antares-Simulator release | `a2g-01.yml` | +| **A2G-02** | Internal change or model library update | `a2g-02.yml` | +| **A2G-03** | New antares-craft release | `a2g-03.yml` | +| **A2G-04** | New GemsPy release | `a2g-04.yml` | + +Each template includes a step-by-step process checklist, versioning steps, and validation requirements. + +--- + +## 4. Pull Request Rules + +### Workflow + +1. Create a branch from `develop` +2. Implement the change +3. Open a PR targeting `develop`, linked to the issue +4. Apply labels (see Section 5) +5. Pass CI and code review +6. Squash and merge + +### PR Title Format + +``` +[PR] : + +[PR] 001: Add STS model support A2G-02 +[PR] 002: Adapt converter to new PyPSA API P2G-03 +[PR] 003: Update Antares legacy thermal model A2G-01 +``` + +### PR Description + +Each PR must include: + +``` +## Process ID +A2G-02 | P2G-01 | N/A + +## Description +What changed and why. + +## Impact Analysis +Affected modules. Breaking changes or backward-compatible? + +## Checklist +- [ ] Tests pass +- [ ] pyproject.toml version bumped if converter logic changed +- [ ] Changelog entry added if library changed +- [ ] COMPATIBILITY.md updated if supported versions changed +``` + +### Merge Strategy + +| Target | Strategy | Who | +|---|---|---| +| `develop` | Squash & Merge | All feature/bugfix/chore PRs | +| `main` | Merge commit | Only from `release/` or `hotfix/` | + +--- + +## 5. Labels + +Every PR must carry at least one label from each group. + +### Change Type + +| Label | Meaning | +|---|---| +| `type:feature` | New feature | +| `type:bugfix` | Bug fix | +| `type:refactor` | Internal restructuring | +| `type:performance` | Performance improvement | +| `type:documentation` | Documentation changes | +| `type:dependency` | Dependency updates | +| `type:hotfix` | Critical post-release fix | + +### Release Impact + +Exactly one release label must be assigned. + +| Label | Meaning | +|---|---| +| `release:major` | Breaking change | +| `release:minor` | New feature, backward-compatible | +| `release:patch` | Bug fix or internal improvement | +| `release:none` | No release impact | + +--- + +## 6. Versioning + +All repositories follow **Semantic Versioning** (`MAJOR.MINOR.PATCH`). + +### PyPSA-to-GEMS-Converter + +| Component | Bump rule | Version file | +|---|---|---| +| Converter (`pyproject.toml`) | Major: Antares major bump / Minor: bug fix, new feature, PyPSA update / Patch: dependency update or library-only change | `pyproject.toml` | +| PyPSA Models Library | Major: new model / Minor: bug fix or improvement / Patch: rename or refactor | `dependencies.json` → `pypsa_models_library_version` | +| PyPSA | Pinned version | `requirements.txt` | +| Antares-Simulator | Pinned version used by CI | `dependencies.json` → `antares_version` | + +### AntaresLegacyModels-to-GEMS-Converter + +| Component | Bump rule | Version file | +|---|---|---| +| Converter (`pyproject.toml`) | Major: Antares major bump / Minor: bug fix, new feature, antares-craft or GemsPy update / Patch: dependency update or library-only change | `pyproject.toml` | +| Antares Legacy Models Library | Major: new model / Minor: bug fix or improvement / Patch: rename or refactor | `dependencies.json` → `antares_legacy_models_library_version` | +| Antares-Simulator | Pinned version used by CI | `dependencies.json` → `antares_simulator_version` | +| antares-craft | Pinned version | `requirements.txt` | +| GemsPy | Pinned version | `requirements.txt` | + +### GEMS + +| Component | Key in `dependencies.json` | +|---|---| +| GEMS Language | `gems_language_version` | +| basic\_models\_library | `basic_models_library_version` | +| antares\_legacy\_models | `antares_legacy_models_version` | +| pypsa\_models | `pypsa_models_version` | +| andromede\_models | `andromede_models_version` | +| Antares-Simulator | `antares_simulator_version` | + +--- + +## 7. Changelogs + +Every repository and every independently versioned model library maintains a dedicated changelog. + +### Repository Changelogs + +- `CHANGELOG.md` at repo root for converter releases + +### Library Changelogs + +| Library | Changelog location | +|---|---| +| PyPSA Models Library | `resources/pypsa_models/CHANGELOG-pypsa_models_library.md` | +| Antares Legacy Models Library | `src/antares_gems_converter/libs/antares_historic/CHANGELOG-antares_legacy_models_library.md` | +| GEMS libraries | `libraries/CHANGELOG-.md` | + +A changelog entry **must be added before tagging a release**. Recommended sections: `Added`, `Changed`, `Fixed`, `Removed`, `Deprecated`. + +--- + +## 8. CI/CD Automation + +### Per-Repository Pipelines + +| Check | GEMS | PyPSA Converter | AntaresLegacy Converter | +|---|---|---|---| +| Linting | `ruff` | `ruff` | `black` | +| Type checking | `mypy` | `mypy` | `mypy` | +| YAML linting | `yamllint` | — | — | +| Unit tests | — | `pytest tests/unit_tests/` | `pytest` (with coverage) | +| E2E tests | `pytest tests/e2e_tests/` | `pytest tests/e2e/` | `pytest tests/antares_historic/` | + +PRs cannot be merged if any required CI check fails. + +### Automated Dependency Monitoring + +Each converter monitors its upstream dependencies on a schedule and opens an issue automatically when a new version is detected. + +| Workflow | Repo | Schedule | Monitors | +|---|---|---|---| +| `check-antares-update` | All three | Daily 06:00 UTC | Antares-Simulator GitHub releases | +| `check-pypsa-update` | PyPSA Converter | Monday 06:00 UTC | PyPSA on PyPI | +| `check-antares-craft-update` | AntaresLegacy Converter | Monday 06:00 UTC | antares-craft on PyPI | +| `check-gemspy-update` | AntaresLegacy Converter | Monday 06:00 UTC | GemsPy on PyPI | + +Each monitoring workflow: + +1. Compares the latest published version against the pinned version in the repo +2. Opens an issue with a triage checklist if a new version is detected +3. Runs the full test suite against the new version +4. Posts the test result as a comment on the issue + +Duplicate issues for the same version are suppressed automatically. + +### Cross-Repository Notifications + +When a model library is updated in a converter, an issue is automatically created in the **GEMS** repository to prompt synchronisation of the shared library YAML. + +| Workflow | From | To | Trigger | +|---|---|---|---| +| `notify-gems-pypsa-models-update` | PyPSA Converter | GEMS | Push to `main` where `pypsa_models_library_version` in `dependencies.json` changed vs last git tag | +| `notify-gems-antares-legacy-models-update` | AntaresLegacy Converter | GEMS | Push to `main` where `antares_legacy_models_library_version` in `dependencies.json` changed vs last git tag | + +The version comparison is performed against the **last git tag**, not the previous commit, to correctly handle multi-commit pushes. Duplicate issues for the same version are suppressed. + +Both workflows require the `GEMS_REPO_PAT` secret (a Personal Access Token with `repo` scope on the GEMS repository). + +--- + +## 9. Release Process + +``` +develop ──── squash PRs ────► create release/vX.Y.Z + │ + ▼ + finalise changelog, bump versions + tag vX.Y.Z on release branch + │ + ▼ + push branch + tag to remote + open PR: release/vX.Y.Z → main + │ + ▼ + merge commit into main + │ + ▼ + publish GitHub release + │ + ▼ + merge release/vX.Y.Z → develop +``` + +### Step-by-step with git commands + +The example below releases version `1.1.0`. + +### 1. Make sure `develop` is up to date + +```bash +git checkout develop +git pull origin develop +``` + +### 2. Create the release branch + +```bash +git checkout -b release/v1.1.0 +``` + +### 3. Finalise the release on the branch + +Update the relevant files: + +- `pyproject.toml` — bump the version field to `1.1.0` +- `dependencies.json` — bump `pypsa_models_library_version` or `antares_legacy_models_library_version` if the library changed +- `CHANGELOG-*.md` — add the release entry with today's date + +Then commit: + +```bash +git add pyproject.toml dependencies.json CHANGELOG-pypsa_models_library.md +git commit -m "release: prepare v1.1.0" +``` + +### 4. Create the tag on the last commit of the release branch + +Only create the tag when all commits on the release branch are final — version bumps, changelog, any last-minute fixes. The tag must point to the last commit. + +```bash +git tag v1.1.0 +``` + +> Do not add any commits after tagging. If you need to fix something, make the commit first, then tag. + +### 5. Push the branch and the tag together + +```bash +git push --atomic origin release/v1.1.0 v1.1.0 +``` + +> `--atomic` ensures both the branch and the tag land on the remote in a single operation — either both succeed or both fail. + +### 6. Open the Release PR + +Open a PR from `release/v1.1.0` targeting `main` on GitHub. + +- Title: `[PR] Release v1.1.0` +- Apply labels: `release:minor` (or `release:major` / `release:patch`) +- Merge strategy: **merge commit** — do not squash (technical requirement, see Section 10) + +### 7. After the PR is merged — publish the GitHub release + +Go to GitHub → Releases → Draft a new release → select the existing tag `v1.1.0` → paste the changelog entry → publish. + +### 8. Sync the release branch back into `develop` + +Open a second PR from `release/v1.1.0` targeting `develop` and merge it. This brings any release preparation commits (version bumps, changelog) back into `develop`. + +> Direct pushes to `develop` are not allowed — this sync must go through a PR like any other change. + +--- + +## 10. Tagging Rules + +- Tags are created on the `release/vX.Y.Z` branch before the PR is merged +- Format: `vX.Y.Z` (e.g. `v1.2.0`, `v0.3.4`) +- Every commit on `main` must correspond to a tag +- The release branch **must** be merged into `main` via a **merge commit** — squash is not allowed. This is a technical requirement for two reasons: + 1. The tag (e.g. `v1.1.0`) is placed on the release branch commit before the PR is merged. A merge commit makes that tagged commit reachable from `main` via `HEAD^2`. With a squash merge, the original release branch commit is discarded and the tag becomes unreachable from `main`, violating the rule above. + 2. The cross-repo notification workflows use `git describe --tags --abbrev=0 HEAD^1` to find the previous release tag. `HEAD^1` is the first parent of the merge commit — the previous tip of `main` — which always has a prior release tag reachable. With a squash merge, subsequent releases would have a squashed (untagged) commit as their `HEAD^1`, causing `git describe` to skip over it and return a stale tag, leading to wrong version comparisons and duplicate notifications. + +--- + +## 11. Hotfix Rules + +For critical issues discovered after a release: + +1. Branch from `main`: `hotfix/vX.Y.Z` +2. Apply the fix +3. Open PR targeting `main` (two approvals recommended) +4. Merge and tag `vX.Y.(Z+1)` +5. **Mandatory**: merge the hotfix back into `develop` + +--- + +## 12. Required GitHub Secrets + +| Secret | Required by | Purpose | +|---|---|---| +| `GEMS_REPO_PAT` | PyPSA Converter, AntaresLegacy Converter | Create issues in the GEMS repository from cross-repo notification workflows | diff --git a/doc/assets/.$4_hybrid_study_scheme.drawio.bkp b/doc/assets/.$4_hybrid_study_scheme.drawio.bkp index 284166ae..0aeeac28 100644 --- a/doc/assets/.$4_hybrid_study_scheme.drawio.bkp +++ b/doc/assets/.$4_hybrid_study_scheme.drawio.bkp @@ -1,6 +1,6 @@ - + @@ -20,11 +20,11 @@ - + - - + + @@ -43,7 +43,7 @@ - + diff --git a/doc/assets/.$4_hybrid_study_scheme.png.bkp b/doc/assets/.$4_hybrid_study_scheme.png.bkp new file mode 100644 index 00000000..11d981c4 Binary files /dev/null and b/doc/assets/.$4_hybrid_study_scheme.png.bkp differ diff --git a/doc/assets/4_hybrid_study_scheme.drawio b/doc/assets/4_hybrid_study_scheme.drawio index 0aeeac28..bf4c4579 100644 --- a/doc/assets/4_hybrid_study_scheme.drawio +++ b/doc/assets/4_hybrid_study_scheme.drawio @@ -1,6 +1,6 @@ - + - + @@ -21,10 +21,10 @@ - + - - + + @@ -42,8 +42,11 @@ - - + + + + + diff --git a/doc/assets/4_hybrid_study_scheme.png b/doc/assets/4_hybrid_study_scheme.png index c1996bee..11d981c4 100644 Binary files a/doc/assets/4_hybrid_study_scheme.png and b/doc/assets/4_hybrid_study_scheme.png differ diff --git a/doc/index.md b/doc/index.md index 8382451b..88a8c05c 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,3 +1,7 @@ +--- +description: GEMS is a high-level, object- and graph-oriented algebraic modelling language for describing and solving energy system optimisation problems. Discover key features, vision, and documentation resources. +--- +
GEMS Logo
diff --git a/doc/template.md b/doc/template.md deleted file mode 100644 index 0af935b6..00000000 --- a/doc/template.md +++ /dev/null @@ -1,64 +0,0 @@ -![Template Banner](assets/template_banner.svg) - -
- - -# Title 1 - -
-
-
- RTE Logo -
RTE - French Transmission System Operator
-
-
- Antares Simulator Logo -
Antares Simulator Team
-
-
-
- -## Sub-Title 2 -Content or text here. - -**Code block example (YAML):** -```yaml -connections: - - component1: generator1 - port1: injection_port - component2: node1 - port2: injection_port - - component1: generator2 - port1: injection_port - component2: node1 - port2: injection_port - - component1: demand - port1: injection_port - component2: node1 - port2: injection_port -``` - -**Code block example (Python):** -```python -print("Hello World") -``` -**Note Example:** - -
-🖊️ Note : This is an important note -
- - -**Simple Equation example:** - - > $3 * parameter_1 * variable_a + variable_b + 56.4 <= variable_4 * 439$ - -**LATEX equation example:** -$$ -3 \cdot \text{parameter\_1} \cdot \text{variable\_a} + \text{variable\_b} + 56.4 \leq \text{variable\_4} \cdot 439 -$$ - diff --git a/libraries/antares_legacy_models.yml b/libraries/antares_legacy_models.yml index c003987c..bf2ef227 100644 --- a/libraries/antares_legacy_models.yml +++ b/libraries/antares_legacy_models.yml @@ -20,7 +20,9 @@ library: fields: - id: flow area-connection: - - injection-field: flow + injection-to-balance: flow + spillage-bound: flow + unsupplied-energy-bound: models: - id: area @@ -57,6 +59,8 @@ library: field: flow definition: -load + + - id: link parameters: - id: capacity_direct @@ -65,12 +69,13 @@ library: - id: capacity_indirect time-dependent: true scenario-dependent: true - - id: flow_direct_hurdle_cost + - id: hurdle_cost_direct time-dependent: true - scenario-dependent: true - - id: flow_indirect_hurdle_cost + scenario-dependent: false + - id: hurdle_cost_indirect time-dependent: true - scenario-dependent: true + scenario-dependent: false + variables: - id: flow_direct lower-bound: 0 @@ -81,8 +86,6 @@ library: upper-bound: capacity_indirect variable-type: continuous - id: flow - lower-bound: -capacity_indirect - upper-bound: capacity_direct variable-type: continuous ports: - id: out_port @@ -96,12 +99,12 @@ library: - port: in_port field: flow definition: -flow + objective-contributions: + - id: objective + expression: sum(hurdle_cost_direct * flow_direct + hurdle_cost_indirect * flow_indirect) constraints: - id: flow_direct_indirect expression: flow = flow_direct - flow_indirect - objective-contributions: - - id: objective - expression: sum(flow_direct * flow_direct_hurdle_cost + flow_indirect * flow_indirect_hurdle_cost) - id: renewable parameters: @@ -120,52 +123,40 @@ library: - id: thermal parameters: - - id: p_min_cluster + - id: minimum_generation_modulation # Timeseries used to define the minimum generation of the cluster by minimum_generation_modulation * unit_count * p_max_unit, this cannot exceed the maximum generation power p_max_cluster (after being increased by p_min_unit). scenario-dependent: true time-dependent: true - - id: p_max_cluster # timeseries that takes outages into account + - id: p_max_cluster # Timeseries that takes outages into account. Used to define the number of available units, which is ceil(p_max_cluster / p_max_unit). scenario-dependent: true time-dependent: true - - id: p_min_unit + - id: p_min_unit # Minimum generation per on unit. Used to increase p_max_cluster so that it is at least equal to p_min_unit times the number of available units, which is ceil(p_max_cluster / p_max_unit). This number of available units does not change when p_max_cluster is increased because ceil((p_min_unit*ceil(p_max_cluster / p_max_unit))/ (p_max_unit*(1-spinning/100)))=ceil(p_max_cluster / p_max_unit) under the assumption that p_min_unit <= p_max_unit*(1-spinning/100). - id: p_max_unit - id: generation_cost - id: startup_cost - id: fixed_cost - id: d_min_up - id: d_min_down - - id: nb_units_min # Equals to ceil(p_min_cluster/p_max_unit), to be done in preprocessing - scenario-dependent: true - time-dependent: true - - id: nb_units_max # Equals to ceil(p_max_cluster/p_max_unit), to be done in preprocessing - scenario-dependent: true - time-dependent: true - - id: nb_units_max_variation_forward - scenario-dependent: true - time-dependent: true - - id: nb_units_max_variation_backward - scenario-dependent: true - time-dependent: true + - id: unit_count + - id: spinning # in percentage, taken into account in p_max_cluster and p_max_unit (except when computing minimum generation) variables: - id: generation - lower-bound: p_min_cluster - upper-bound: p_max_cluster + lower-bound: min(max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster / p_max_unit)), minimum_generation_modulation * unit_count * p_max_unit) # real expression before simplification : min(upper-bound(generation),minimum_generation_modulation * unit_count * p_max_unit) = min(max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster*(1-spinning/100) / (p_max_unit*(1-spinning/100)))), minimum_generation_modulation * unit_count * p_max_unit) + upper-bound: max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster / p_max_unit)) # real expression before simplification : max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster*(1-spinning/100) / (p_max_unit*(1-spinning/100)))) variable-type: continuous - id: nb_units_on - lower-bound: nb_units_min - upper-bound: nb_units_max - variable-type: integer + lower-bound: ceil(min(p_max_cluster/p_max_unit, minimum_generation_modulation * unit_count * p_max_unit/(p_max_unit*(1-spinning/100)))) # real expression before simplification : ceil(lower-bound(generation)/(p_max_unit*(1-spinning/100))) = ceil(min(max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster / p_max_unit)), minimum_generation_modulation * unit_count * p_max_unit)/(p_max_unit*(1-spinning/100))) + upper-bound: ceil(p_max_cluster/p_max_unit) # real expression before simplification : ceil(upper-bound(generation)/(p_max_unit*(1-spinning/100))) = ceil(max(p_max_cluster*(1-spinning/100), p_min_unit * ceil(p_max_cluster*(1-spinning/100) / (p_max_unit*(1-spinning/100))))/(p_max_unit*(1-spinning/100))) + variable-type: continuous #integer - id: nb_starting lower-bound: 0 - upper-bound: nb_units_max - variable-type: integer + variable-type: continuous #integer - id: nb_stopping lower-bound: 0 - upper-bound: nb_units_max - variable-type: integer + variable-type: continuous #integer - id: nb_failing lower-bound: 0 - upper-bound: nb_units_max - variable-type: integer + upper-bound: max(0, (ceil(p_max_cluster/p_max_unit))[t-1] - (ceil(p_max_cluster/p_max_unit))) + variable-type: continuous #integer ports: - id: balance_port type: flow @@ -175,19 +166,17 @@ library: definition: generation constraints: - id: max_generation - expression: generation <= nb_units_on * p_max_unit + expression: generation <= nb_units_on * p_max_unit*(1-spinning/100) - id: min_generation expression: generation >= nb_units_on * p_min_unit - id: on_units_dynamics expression: nb_units_on = nb_units_on[t-1] + nb_starting - nb_stopping - id: nb_failing_lower_than_stopping expression: nb_failing <= nb_stopping - - id: nb_failing_lower_than_max_variation - expression: nb_failing <= nb_units_max_variation_forward - id: min_up_duration expression: sum(t-d_min_up + 1 .. t, nb_starting - nb_failing) <= nb_units_on - id: min_down_duration - expression: sum(t-d_min_down + 1 .. t, nb_stopping) <= nb_units_max[t-d_min_down] - nb_units_on + sum(t-d_min_down + 1 .. t, nb_units_max_variation_backward) + expression: sum(t-d_min_down + 1 .. t, nb_stopping) <= ((ceil(p_max_cluster/p_max_unit)))[t-d_min_down] - nb_units_on + sum(t-d_min_down + 1 .. t, max(0, ceil(p_max_cluster/p_max_unit) - (ceil(p_max_cluster/p_max_unit))[t-1])) objective-contributions: - id: objective expression: sum(generation_cost * generation + startup_cost * nb_starting + fixed_cost * nb_units_on) @@ -227,6 +216,15 @@ library: - id: initial_level time-dependent: false scenario-dependent: true + - id: cost_injection + time-dependent: true + scenario-dependent: true + - id: cost_withdrawal + time-dependent: true + scenario-dependent: true + - id: cost_level + time-dependent: true + scenario-dependent: true variables: - id: p_injection lower-bound: 0 @@ -250,5 +248,8 @@ library: constraints: - id: initial_level_constraint expression: level[0] = initial_level * reservoir_capacity - - id: level_dynamic_constraint - expression: level[t+1] = level + efficiency_injection * p_injection - efficiency_withdrawal * p_withdrawal + inflows \ No newline at end of file + - id: level_equation + expression: level[t+1] = level + efficiency_injection * p_injection - efficiency_withdrawal * p_withdrawal + inflows + objective-contributions: + - id: objective + expression: sum(cost_injection * p_injection + cost_withdrawal * p_withdrawal + cost_level * level) \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 00000000..e93187de --- /dev/null +++ b/main.py @@ -0,0 +1,14 @@ +# Copyright (c) 2025, RTE (https://www.rte-france.com) +# +# This file is part of the Antares project. + +from pathlib import Path + + +def define_env(env): + """MkDocs macros hook — exposes variables from the versions/ directory.""" + versions_file = Path(__file__).parent / "versions" / "antares-simulator.txt" + for line in versions_file.read_text().splitlines(): + key, _, value = line.partition("=") + if key.strip(): + env.variables[key.strip().lower()] = value.strip() diff --git a/mkdocs.yml b/mkdocs.yml index 03d23956..8ca71b53 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,12 @@ docs_dir: doc +exclude_docs: | + documentation_env/ + 2_Getting_Started/Tutorial_2_PyPSA_eur/* site_name: GEMS - Generic Energy system Modelling Scheme +site_url: https://gems-energy.readthedocs.io/en/latest/ +site_description: "GEMS (Generic Energy system Modelling Scheme) is a graph-based algebraic modelling language for defining and solving energy system optimisation problems." +site_author: "Antares Simulator Team - RTE" +copyright: "Copyright © 2026 RTE" repo_url: https://github.com/AntaresSimulatorTeam/GEMS edit_uri: edit/doc/doc/ @@ -58,7 +65,12 @@ extra_css: plugins: - search + - macros: + module_name: main - git-revision-date-localized: + exclude: + - documentation_env/* + - 2_Getting_Started/Tutorial_2_PyPSA_eur/pypsa-eur/* enable_creation_date: true enable_git_follow: true type: timeago @@ -120,11 +132,18 @@ nav: - Current Limitations of the Converter: 4_Interoperability/1_PyPSA_to_GEMS_converter/4_current_limitations.md - Step-by-Step Guide Manually Executing a Simulation in GEMS Modeler: 4_Interoperability/1_PyPSA_to_GEMS_converter/5_step_by_step_guide.md - Comparing Results Between GEMS Modeler and PyPSA: 4_Interoperability/1_PyPSA_to_GEMS_converter/6_comparing_results.md - #- Antares Legacy Format: 4_Interoperability/2_antares_legacy.md - - Antares Hybrid Mode: 4_Interoperability/3_hybrid.md + - Antares Hybrid Mode: + - Overview: 4_Interoperability/3_hybrid/1_overview.md + - Coupling GEMS Components with Legacy Areas: 4_Interoperability/3_hybrid/2_hybrid_connections.md + - Run a Hybrid Study: 4_Interoperability/3_hybrid/4_how_to_run.md + - Outputs: 4_Interoperability/3_hybrid/3_outputs.md + - Simple Example: 4_Interoperability/3_hybrid/5_example.md + - Limitations: 4_Interoperability/3_hybrid/6_limitations.md - Examples: - Adequacy Example: 5_Examples/1_adequacy_example.md - Support & Contributing: - FAQ: 6_Support_Contributing/1_faq.md - Contact: 6_Support_Contributing/2_contact.md - - Contributing: 6_Support_Contributing/3_contributing.md \ No newline at end of file + - For Developers: + - Contributing: 6_Support_Contributing/3_contributing.md + - PR Workflow: 6_Support_Contributing/4_pr_management.md \ No newline at end of file diff --git a/requirements-doc.txt b/requirements-doc.txt index 31996258..a7d6ff62 100644 --- a/requirements-doc.txt +++ b/requirements-doc.txt @@ -1,3 +1,5 @@ mkdocs mkdocs-material mkdocs-git-revision-date-localized-plugin +mkdocs-redirects +mkdocs-macros-plugin diff --git a/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment/input/system.yml b/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment/input/system.yml index 3df941b3..7bf410e7 100644 --- a/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment/input/system.yml +++ b/resources/Documentation_Examples/QSE/QSE_2_Unit_Commitment/input/system.yml @@ -54,27 +54,19 @@ system: time-dependent: false scenario-dependent: false value: 12 - - id: p_min_cluster - time-dependent: false - scenario-dependent: false - value: 0 - id: p_max_cluster time-dependent: false scenario-dependent: false value: 100 - - id: nb_units_max + - id: unit_count time-dependent: false scenario-dependent: false value: 10 - - id: nb_units_min - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_forward + - id: spinning time-dependent: false scenario-dependent: false value: 0 - - id: nb_units_max_variation_backward + - id: minimum_generation_modulation time-dependent: false scenario-dependent: false value: 0 diff --git a/resources/e2e_studies/antares_legacy_models/test_sts/GEMS-STS-Test/input/system.yml b/resources/e2e_studies/antares_legacy_models/test_sts/GEMS-STS-Test/input/system.yml index 83f75d66..33360ed6 100644 --- a/resources/e2e_studies/antares_legacy_models/test_sts/GEMS-STS-Test/input/system.yml +++ b/resources/e2e_studies/antares_legacy_models/test_sts/GEMS-STS-Test/input/system.yml @@ -13,7 +13,7 @@ system: time-dependent: false scenario-dependent: false value: 10000 - + - id: load_bus model: antares_legacy_models.load @@ -27,6 +27,14 @@ system: model: antares_legacy_models.thermal parameters: + - id: minimum_generation_modulation + time-dependent: false + scenario-dependent: false + value: 0 + - id: p_max_cluster + time-dependent: false + scenario-dependent: false + value: 1000 - id: p_min_unit time-dependent: false scenario-dependent: false @@ -55,27 +63,11 @@ system: time-dependent: false scenario-dependent: false value: 12 - - id: p_min_cluster - time-dependent: false - scenario-dependent: false - value: 0 - - id: p_max_cluster - time-dependent: false - scenario-dependent: false - value: 1000 - - id: nb_units_max + - id: unit_count time-dependent: false scenario-dependent: false value: 10 - - id: nb_units_min - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_forward - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_backward + - id: spinning time-dependent: false scenario-dependent: false value: 0 @@ -84,6 +76,14 @@ system: model: antares_legacy_models.thermal parameters: + - id: minimum_generation_modulation + time-dependent: false + scenario-dependent: false + value: 0 + - id: p_max_cluster + time-dependent: false + scenario-dependent: false + value: 500 - id: p_min_unit time-dependent: false scenario-dependent: false @@ -112,27 +112,11 @@ system: time-dependent: false scenario-dependent: false value: 5 - - id: p_min_cluster - time-dependent: false - scenario-dependent: false - value: 0 - - id: p_max_cluster - time-dependent: false - scenario-dependent: false - value: 500 - - id: nb_units_max + - id: unit_count time-dependent: false scenario-dependent: false value: 5 - - id: nb_units_min - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_forward - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_backward + - id: spinning time-dependent: false scenario-dependent: false value: 0 @@ -145,10 +129,6 @@ system: time-dependent: false scenario-dependent: false value: 500 - - id: initial_level - time-dependent: false - scenario-dependent: false - value: 0.5 - id: injection_nominal_capacity time-dependent: false scenario-dependent: false @@ -185,6 +165,22 @@ system: time-dependent: false scenario-dependent: false value: 0 + - id: initial_level + time-dependent: false + scenario-dependent: false + value: 0.5 + - id: cost_injection + time-dependent: false + scenario-dependent: false + value: 0 + - id: cost_withdrawal + time-dependent: false + scenario-dependent: false + value: 0 + - id: cost_level + time-dependent: false + scenario-dependent: false + value: 0 connections: @@ -204,4 +200,3 @@ system: component2: my-sts port1: balance_port port2: injection_port - diff --git a/resources/e2e_studies/antares_legacy_models/test_thermal_clusters/GEMS-Thermal-Test/input/system.yml b/resources/e2e_studies/antares_legacy_models/test_thermal_clusters/GEMS-Thermal-Test/input/system.yml index c2469ec2..2ecf629d 100644 --- a/resources/e2e_studies/antares_legacy_models/test_thermal_clusters/GEMS-Thermal-Test/input/system.yml +++ b/resources/e2e_studies/antares_legacy_models/test_thermal_clusters/GEMS-Thermal-Test/input/system.yml @@ -13,7 +13,7 @@ system: time-dependent: false scenario-dependent: false value: 10000 - + - id: load_bus model: antares_legacy_models.load @@ -27,6 +27,14 @@ system: model: antares_legacy_models.thermal parameters: + - id: minimum_generation_modulation + time-dependent: false + scenario-dependent: false + value: 0 + - id: p_max_cluster + time-dependent: false + scenario-dependent: false + value: 1000 - id: p_min_unit time-dependent: false scenario-dependent: false @@ -55,27 +63,11 @@ system: time-dependent: false scenario-dependent: false value: 12 - - id: p_min_cluster - time-dependent: false - scenario-dependent: false - value: 0 - - id: p_max_cluster - time-dependent: false - scenario-dependent: false - value: 1000 - - id: nb_units_max + - id: unit_count time-dependent: false scenario-dependent: false value: 10 - - id: nb_units_min - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_forward - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_backward + - id: spinning time-dependent: false scenario-dependent: false value: 0 @@ -84,6 +76,14 @@ system: model: antares_legacy_models.thermal parameters: + - id: minimum_generation_modulation + time-dependent: false + scenario-dependent: false + value: 0 + - id: p_max_cluster + time-dependent: false + scenario-dependent: false + value: 500 - id: p_min_unit time-dependent: false scenario-dependent: false @@ -112,27 +112,11 @@ system: time-dependent: false scenario-dependent: false value: 5 - - id: p_min_cluster - time-dependent: false - scenario-dependent: false - value: 0 - - id: p_max_cluster - time-dependent: false - scenario-dependent: false - value: 500 - - id: nb_units_max + - id: unit_count time-dependent: false scenario-dependent: false value: 5 - - id: nb_units_min - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_forward - time-dependent: false - scenario-dependent: false - value: 0 - - id: nb_units_max_variation_backward + - id: spinning time-dependent: false scenario-dependent: false value: 0 @@ -151,4 +135,3 @@ system: component2: th2 port1: balance_port port2: balance_port - diff --git a/resources/yaml-loader-example.yaml b/resources/yaml-loader-example.yaml deleted file mode 100644 index 2cdead7a..00000000 --- a/resources/yaml-loader-example.yaml +++ /dev/null @@ -1,44 +0,0 @@ -sections: - - title: "Basic Configuration" - content: | - This file defines the default parameters. - Values must be modified manually. - - Main parameters: - - database_host: localhost - - database_port: 5432 - - debug_mode: false - - log_level: info - - - title: "Advanced Options" - content: | - Advanced options are reserved for expert users. - Use with caution. - - Advanced options: - - enable_caching: true - - cache_ttl: 3600 - - max_connections: 100 - - timeout_seconds: 30 - - enable_compression: true - - - title: "Network Configuration" - content: | - Network and communication parameters. - - Network: - - server_address: 0.0.0.0 - - api_port: 8080 - - websocket_port: 8081 - - ssl_enabled: true - - certificate_path: /path/to/cert.pem - - - title: "Additional Documentation" - content: | - For more information, please refer to the official documentation. - - Resources: - - Main documentation: https://docs.example.com - - User guide: https://docs.example.com/guide - - API Reference: https://api.example.com/docs - - Community support: https://github.com/example/repo/discussions diff --git a/tests/e2e_tests/env.py b/tests/e2e_tests/env.py index 5698adfc..6d61038a 100644 --- a/tests/e2e_tests/env.py +++ b/tests/e2e_tests/env.py @@ -9,6 +9,7 @@ OBJECTIVE_ATOL = 1e-4 +OBJECTIVE_RTOL = 0.01 @dataclass(frozen=True) @@ -24,6 +25,15 @@ class EnvironmentPaths: antares_modeler_bin: Path +def _read_antares_version(repo_root: Path) -> str: + versions_file = repo_root / "versions" / "antares-simulator.txt" + for line in versions_file.read_text().splitlines(): + key, _, value = line.partition("=") + if key.strip() == "ANTARES_SIMULATOR_VERSION": + return value.strip() + raise ValueError(f"ANTARES_SIMULATOR_VERSION not found in {versions_file}") + + def get_paths() -> EnvironmentPaths: """ Central place for: @@ -39,7 +49,8 @@ def get_paths() -> EnvironmentPaths: doc_examples_path = repo_root / "resources" / "Documentation_Examples" / "QSE" - antares_root = repo_root / "antares-9.3.2-Ubuntu-22.04" + antares_version = _read_antares_version(repo_root) + antares_root = repo_root / f"antares-{antares_version}-Ubuntu-22.04" antares_solver_bin = antares_root / "bin" / "antares-solver" antares_modeler_bin = antares_root / "bin" / "antares-modeler" diff --git a/tests/e2e_tests/test_antares_legacy_models_equivalence.py b/tests/e2e_tests/test_antares_legacy_models_equivalence.py index 17506ed7..b68a81ae 100644 --- a/tests/e2e_tests/test_antares_legacy_models_equivalence.py +++ b/tests/e2e_tests/test_antares_legacy_models_equivalence.py @@ -2,7 +2,7 @@ import pytest -from .env import OBJECTIVE_ATOL +from .env import OBJECTIVE_RTOL from .utils import ( copy_antares_zip_to_tmp, copy_model_library, @@ -48,4 +48,6 @@ def test_study_equivalence(tmp_root, paths, antares_zip: str, gems_study: str, s logger.info("GEMS objective : %s", gems_objective) logger.info("Antares objective : %s", antares_objective) - assert gems_objective == pytest.approx(antares_objective, abs=OBJECTIVE_ATOL) + # The GEMS thermal model uses continuous relaxation of integer unit-commitment variables, + # so the LP objective may be slightly lower than the Antares MIP objective (< 1% gap). + assert gems_objective == pytest.approx(antares_objective, rel=OBJECTIVE_RTOL) diff --git a/tests/e2e_tests/test_doc_qse_examples.py b/tests/e2e_tests/test_doc_qse_examples.py index ae0c4192..cb219342 100644 --- a/tests/e2e_tests/test_doc_qse_examples.py +++ b/tests/e2e_tests/test_doc_qse_examples.py @@ -41,7 +41,7 @@ def prepare_and_run_doc_study( "study_name, library_filename, expected_objective", [ ("QSE_1_Adequacy", "basic_models_library.yml", 7990.0), - ("QSE_2_Unit_Commitment", "antares_legacy_models.yml", 817550.0), + ("QSE_2_Unit_Commitment", "antares_legacy_models.yml", 798277.0), ], ) def test_doc_qse_examples(tmp_root, paths, study_name: str, library_filename: str, expected_objective: float) -> None: diff --git a/versions/antares-simulator.txt b/versions/antares-simulator.txt index 2dcba897..5571470d 100644 --- a/versions/antares-simulator.txt +++ b/versions/antares-simulator.txt @@ -1 +1 @@ -ANTARES_SIMULATOR_VERSION=9.3.2 +ANTARES_SIMULATOR_VERSION=10.0.1