-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Damien Jeandemange <[email protected]>
- Loading branch information
1 parent
23a989a
commit b0bd5e3
Showing
49 changed files
with
2,786 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
name: CI | ||
|
||
on: | ||
pull_request: | ||
workflow_dispatch: | ||
inputs: | ||
upload_artifacts: | ||
description: 'Upload build artifacts' | ||
required: true | ||
default: false | ||
type: boolean | ||
|
||
permissions: { } | ||
|
||
jobs: | ||
build: | ||
name: Build on ${{ matrix.os }} | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
|
||
env: | ||
DISPLAY: :99 | ||
|
||
steps: | ||
- name: Checkout sources | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.12' | ||
cache: 'pip' | ||
|
||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
- name: Xvfb (Linux only) | ||
if: matrix.os == 'ubuntu-latest' | ||
run: | | ||
sudo apt-get update -y | ||
sudo apt-get install -y xvfb | ||
Xvfb -ac $DISPLAY -screen 0 1280x1024x24 > /dev/null 2>&1 & | ||
- name: Test with pytest | ||
run: | | ||
coverage run --branch -m pytest tests | ||
coverage xml | ||
coverage report | ||
- name: SonarCloud Scan (Linux only) | ||
if: matrix.os == 'ubuntu-latest' | ||
uses: SonarSource/[email protected] | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any | ||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
|
||
- name: Build application with PyInstaller | ||
run: pyinstaller -y yagat.spec | ||
|
||
- name: Upload application Artifact | ||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.upload_artifacts }} | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: yagat-${{ matrix.os }} | ||
path: dist/yagat* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
*.iml | ||
*.zip | ||
.idea | ||
venv | ||
/build/ | ||
/dist/ | ||
__pycache__/ | ||
/.coverage | ||
/coverage.xml | ||
/junit/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,97 @@ | ||
# YAGAT | ||
|
||
Yet Another Grid Analysis Tool | ||
**Y**et **A**nother **G**rid **A**nalysis **T**ool | ||
|
||
## Overview | ||
|
||
YAGAT provides a graphical user interface built on top of the [PowSyBl](https://www.powsybl.org) open source grid analysis libraries. | ||
|
||
With YAGAT no computer science skill is required: just download the application and run it. | ||
|
||
Today with YAGAT you can: | ||
- Load grid models from the various formats supported by [PowSyBl](https://www.powsybl.org): | ||
- CIM/CGMES | ||
- UCTE-DEF | ||
- IEEE-CDF | ||
- MATPOWER | ||
- Siemens PSS®E | ||
- Display and navigate the grid model with electrical buses represented in tabular form | ||
- Run a Load Flow, visualize solved bus voltages and branch flows | ||
|
||
## Installation | ||
|
||
### Binary releases | ||
|
||
Binary releases are provided for Windows, Linux and macOS on the [releases page](https://github.com/jeandemanged/yagat/releases). | ||
No additional software is required for installation. | ||
Download and extract the zip archive for your platform, then run YAGAT. | ||
|
||
### Building from source | ||
|
||
With Python 3.12 and e.g. using a Virtual Environment and `pip`. | ||
|
||
```bash | ||
# clone the git repository | ||
git clone https://github.com/jeandemanged/yagat.git | ||
cd yagat | ||
``` | ||
|
||
```bash | ||
# install requirements | ||
python -m venv venv | ||
. venv/bin/activate | ||
pip install -r requirements.txt | ||
``` | ||
|
||
```bash | ||
# build the application | ||
pyinstaller -y yagat.spec | ||
``` | ||
|
||
YAGAT is then available for your platform in the `dist` directory. | ||
|
||
## Quick Start | ||
|
||
- **Open a sample network**: Go to `File` | `Open Sample network` | `IEEE 9 Bus` to load a sample grid model. | ||
- **Navigate the grid**: Use the tree view on the left to browse through the network model and its elements. | ||
- **Run the Load Flow**: Select `Run` | `Load Flow` to execute the analysis. | ||
- Once completed, view the solved bus voltages and branch flows for insights into the grid's state. | ||
|
||
## Roadmap | ||
|
||
YAGAT today lacks many features, but you may already find it useful. What is planned for the future is: | ||
|
||
### Short-Term to Mid-Term Plans: | ||
- **General**: A log view | ||
- **Grid Model Navigation**: Tabular views per equipment type | ||
- **Grid Model Updates**: Adjust grid configurations, such as opening/closing switches, changing generator set points, etc. | ||
- **Load Flow**: | ||
- Add ability to save/load the Load Flow parameters | ||
- View Load Flow reports in order to troubleshoot e.g. non-convergence | ||
|
||
### Future Plans: | ||
- **Security Analysis**: | ||
- Configure a list of contingencies to simulate | ||
- Run contingency analysis | ||
- View contingency violations | ||
|
||
## Under the Hood | ||
|
||
YAGAT is: | ||
- **Written in Python**: a high-level, general-purpose programming language. | ||
- **Using [PyPowSyBl](https://pypowsybl.readthedocs.io/en/latest/index.html)**: Provides the core grid analysis functionalities. | ||
- **Using [Tkinter](https://wiki.python.org/moin/TkInter)**: Supplies the graphical user interface. | ||
- **Using [Tksheet](https://github.com/ragardner/tksheet)**: An amazing tkinter table widget. | ||
- **Using [PyInstaller](https://pyinstaller.org/en/stable/)**: Packages the application. | ||
|
||
## Data Confidentiality | ||
|
||
We take data confidentiality seriously. | ||
All data processed by the application remains on the user's local machine and is not transmitted to any external servers. | ||
This ensures complete data privacy for users working with sensitive grid models. | ||
|
||
## Contributing and Support | ||
|
||
Should you encounter any issues with YAGAT, please let us know. | ||
We welcome contributions, ideas, and feedback. Please open an [issue](https://github.com/jeandemanged/yagat/issues) | ||
or [pull request](https://github.com/jeandemanged/yagat/pulls) to get involved. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# | ||
# This file is autogenerated by pip-compile with Python 3.12 | ||
# by the following command: | ||
# | ||
# pip-compile requirements.in | ||
# | ||
altgraph==0.17.4 | ||
# via pyinstaller | ||
colorama==0.4.6 | ||
# via pytest | ||
coverage[toml]==7.6.4 | ||
# via pytest-cov | ||
iniconfig==2.0.0 | ||
# via pytest | ||
networkx==3.4.2 | ||
# via pypowsybl | ||
numpy==2.1.3 | ||
# via pandas | ||
packaging==24.2 | ||
# via | ||
# pyinstaller | ||
# pyinstaller-hooks-contrib | ||
# pytest | ||
pandas==2.2.3 | ||
# via pypowsybl | ||
pefile==2023.2.7 | ||
# via pyinstaller | ||
pillow==11.0.0 | ||
# via -r requirements.in | ||
pluggy==1.5.0 | ||
# via pytest | ||
prettytable==3.12.0 | ||
# via pypowsybl | ||
pyinstaller==6.11.0 | ||
# via -r requirements.in | ||
pyinstaller-hooks-contrib==2024.9 | ||
# via pyinstaller | ||
pypowsybl==1.8.1 | ||
# via -r requirements.in | ||
pytest==8.3.3 | ||
# via | ||
# -r requirements.in | ||
# pytest-cov | ||
pytest-cov==6.0.0 | ||
# via -r requirements.in | ||
python-dateutil==2.9.0.post0 | ||
# via pandas | ||
pytz==2024.2 | ||
# via pandas | ||
pywin32-ctypes==0.2.3 | ||
# via pyinstaller | ||
six==1.16.0 | ||
# via python-dateutil | ||
tksheet==7.2.21 | ||
# via -r requirements.in | ||
tzdata==2024.2 | ||
# via pandas | ||
wcwidth==0.2.13 | ||
# via prettytable | ||
|
||
# The following packages are considered to be unsafe in a requirements file: | ||
# setuptools |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
sonar.projectKey=jeandemanged_yagat | ||
sonar.organization=jeandemanged | ||
|
||
sonar.sources=yagat | ||
sonar.tests=tests | ||
sonar.python.coverage.reportPaths=coverage.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# | ||
# Copyright (c) 2024, Damien Jeandemange (https://github.com/jeandemanged) | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# SPDX-License-Identifier: MPL-2.0 | ||
# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# | ||
# Copyright (c) 2024, Damien Jeandemange (https://github.com/jeandemanged) | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# SPDX-License-Identifier: MPL-2.0 | ||
# | ||
import tkinter as tk | ||
|
||
import pypowsybl.network as pn | ||
import pytest | ||
|
||
from yagat.app_context import AppContext | ||
|
||
|
||
class TestListener: | ||
|
||
__test__ = False | ||
|
||
def __init__(self, context: AppContext): | ||
self._status_text_from_listener = None | ||
self._network_from_listener = None | ||
self._selection_from_listener = None | ||
self._selected_tab_from_listener = None | ||
context.add_status_text_listener(lambda value: self.status_text_listener(value)) | ||
context.add_network_changed_listener(lambda value: self.network_listener(value)) | ||
context.add_selection_changed_listener(lambda value: self.selection_listener(value)) | ||
context.add_tab_changed_listener(lambda value: self.selected_tab_listener(value)) | ||
|
||
def status_text_listener(self, value): | ||
self._status_text_from_listener = value | ||
|
||
def network_listener(self, value): | ||
self._network_from_listener = value | ||
|
||
def selection_listener(self, value): | ||
self._selection_from_listener = value | ||
|
||
def selected_tab_listener(self, value): | ||
self._selected_tab_from_listener = value | ||
|
||
@property | ||
def status_text_from_listener(self): | ||
return self._status_text_from_listener | ||
|
||
@property | ||
def network_from_listener(self) -> pn.Network: | ||
return self._network_from_listener | ||
|
||
@property | ||
def selection_from_listener(self): | ||
return self._selection_from_listener | ||
|
||
@property | ||
def selected_tab_from_listener(self): | ||
return self._selected_tab_from_listener | ||
|
||
|
||
class TestAppContext: | ||
|
||
@pytest.fixture | ||
def context(self): | ||
context = AppContext(tk.Tk()) | ||
yield context | ||
|
||
def test_initial_state(self, context): | ||
assert context.tk_root is not None | ||
assert context.network is None | ||
assert context.network_structure is None | ||
assert context.selection[0] is None | ||
assert context.selection[1] is None | ||
assert context.selection[2] is None | ||
assert context.status_text == 'Welcome' | ||
|
||
def test_status_text(self, context): | ||
test = TestListener(context) | ||
context.status_text = 'test status text' | ||
assert test.status_text_from_listener == 'test status text' | ||
|
||
def test_network(self, context): | ||
test = TestListener(context) | ||
context.network = pn.create_ieee9() | ||
assert test.network_from_listener.name == 'ieee9cdf' | ||
context.network = None | ||
assert test.network_from_listener is None | ||
|
||
def test_selection(self, context): | ||
test = TestListener(context) | ||
context.selection = 'test selection' | ||
assert test.selection_from_listener == 'test selection' | ||
context.selection = None | ||
assert test.selection_from_listener is None | ||
|
||
def test_selected_tab(self, context): | ||
test = TestListener(context) | ||
context.selected_tab = 'test selected tab' | ||
assert test.selected_tab_from_listener == 'test selected tab' | ||
context.selected_tab = None | ||
assert test.selected_tab_from_listener is None |
Oops, something went wrong.