Skip to content

Commit

Permalink
merge origin/main
Browse files Browse the repository at this point in the history
Signed-off-by: Thijs Baaijen <[email protected]>
  • Loading branch information
Thijss committed Feb 3, 2025
2 parents 62c6cde + 00a7d2d commit 676fd30
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 120 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/citations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0

name: Validate citation

on:
# run pipeline on push event of main branch, or when CITATIONS path has changed
push:
branches:
- main
paths:
- CITATION.cff
- .github/workflows/citations.yml
pull_request:
paths:
- CITATION.cff
- .github/workflows/citations.yml
# run pipeline from another workflow
workflow_call:
# run this workflow manually from the Actions tab
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-citations
cancel-in-progress: true

jobs:
validate-citations:
runs-on: ubuntu-24.04
steps:
- name: checkout
uses: actions/checkout@v4
- name: Install R
run: |
sudo apt-get update && sudo apt-get install -y r-base
- name: Validate CITATION.cff
uses: dieghernan/cff-validator@v4
174 changes: 174 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0

cff-version: 1.2.0
message: "If you are using Power Grid Model in your research work, please consider citing our library as below."

title: "PowerGridModel/power-grid-model-ds"
url: "https://github.com/PowerGridModel/power-grid-model-ds"
license: "MPL-2.0"
authors:
- family-names: "Schouten"
given-names: "Jaap"
email: [email protected]
affiliation: "Alliander"
- family-names: "Baaijen"
given-names: "Thijs"
email: [email protected]
affiliation: "Alliander"
- family-names: "Koppen"
given-names: "Vincent"
email: [email protected]
- family-names: "Voort"
name-particle: "van der"
given-names: "Sven"
email: [email protected]
- name: "Contributors to the LF Energy project Power Grid Model"
contact:
- name: "LF Energy project Power Grid Model"
email: "[email protected]"

references:
- title: "PowerGridModel/power-grid-model"
repository-code: "https://github.com/PowerGridModel/power-grid-model"
doi: "10.5281/zenodo.8054429"
license: "MPL-2.0"
type: software-code
authors:
- family-names: "Xiang"
given-names: "Yu"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Salemink"
given-names: "Peter"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Westering"
name-particle: "van"
given-names: "Werner"
email: [email protected]
affiliation: "Alliander"
- family-names: "Bharambe"
given-names: "Nitish"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Govers"
given-names: "Martinus"
email: "[email protected]"
affiliation: "Alliander"
orcid: "https://orcid.org/0009-0008-6890-8353"
- family-names: "Bogaard"
name-particle: "van den"
given-names: "Jonas"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Stoeller"
given-names: "Bram"
- family-names: "Wang"
given-names: "Zhen"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Guo"
given-names: "Jerry"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Jagutis"
given-names: "Laurynas"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Wang"
given-names: "Chenguang"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Raalte"
name-particle: "van"
given-names: "Marc"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Figueroa Manrique"
given-names: "Santiago"
email: "[email protected]"
affiliation: "Alliander"
- name: "Contributors to the LF Energy project Power Grid Model"

- title: "Power grid model: A high-performance distribution grid calculation library"
doi: "10.1049/icp.2023.0633"
authors:
- family-names: "Xiang"
given-names: "Yu"
email: [email protected]
affiliation: "Alliander"
- family-names: "Salemink"
given-names: "Peter"
email: [email protected]
affiliation: "Alliander"
- family-names: "Stoeller"
given-names: "Bram"
- family-names: "Bharambe"
given-names: "Nitish"
email: [email protected]
affiliation: "Alliander"
- family-names: "Westering"
name-particle: "van"
given-names: "Werner"
email: [email protected]
affiliation: "Alliander"
conference:
name: "CIRED 2023 - The 27th International Conference and Exhibition on Electricity Distribution"
type: conference-paper
year: 2023
volume: 2023
pages: "1-5"

- title: "PowerGridModel/power-grid-model-io"
repository-code: "https://github.com/PowerGridModel/power-grid-model-io"
doi: "10.5281/zenodo.8059257"
license: "MPL-2.0"
type: software-code
authors:
- family-names: "Xiang"
given-names: "Yu"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Salemink"
given-names: "Peter"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Bharambe"
given-names: "Nitish"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Govers"
given-names: "Martinus"
email: "[email protected]"
affiliation: "Alliander"
orcid: "https://orcid.org/0009-0008-6890-8353"
- family-names: "Bogaard"
name-particle: "van den"
given-names: "Jonas"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Stoeller"
given-names: "Bram"
- family-names: "Wang"
given-names: "Zhen"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Guo"
given-names: "Jerry"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Jagutis"
given-names: "Laurynas"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Wang"
given-names: "Chenguang"
email: "[email protected]"
affiliation: "Alliander"
- family-names: "Figueroa Manrique"
given-names: "Santiago"
email: "[email protected]"
affiliation: "Alliander"
- name: "Contributors to the LF Energy project Power Grid Model"
12 changes: 6 additions & 6 deletions tests/performance/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
"dtype = [('id', '<i8'), ('test_int', '<i8'), ('test_float', '<f8'), ('test_str', '<U50'), ('test_bool', '?')]; "
)

SETUP_CODES = {
"structured": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.zeros({array_size}, dtype=dtype)",
"rec": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.recarray(({array_size},),dtype=dtype)",
"fancy": "from tests.conftest import FancyTestArray; input_array=FancyTestArray.zeros({array_size});"
+ "import numpy as np;input_array.id = np.arange({array_size})",
ARRAY_SETUP_CODES = {
"structured": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.zeros({size}, dtype=dtype)",
"rec": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.recarray(({size},),dtype=dtype)",
"fancy": "from tests.conftest import FancyTestArray; input_array=FancyTestArray.zeros({size});"
+ "import numpy as np;input_array.id = np.arange({size})",
}

GRAPH_SETUP_CODES = {
"rustworkx": "from power_grid_model_ds import Grid;"
+ "from power_grid_model_ds.generators import RadialGridGenerator;"
+ "from power_grid_model_ds.graph_models import RustworkxGraphModel;"
+ "grid=RadialGridGenerator(nr_nodes={graph_size}, grid_class=Grid, graph_model=RustworkxGraphModel).run()",
+ "grid=RadialGridGenerator(nr_nodes={size}, grid_class=Grid, graph_model=RustworkxGraphModel).run()",
}

SINGLE_REPEATS = 1000
Expand Down
101 changes: 29 additions & 72 deletions tests/performance/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,100 +4,57 @@

import inspect
import timeit
from typing import Generator
from itertools import product
from typing import Generator, Union

from tests.performance._constants import GRAPH_SETUP_CODES, SETUP_CODES


def do_performance_test(code_to_test: str | dict[str, str], array_sizes: list[int], repeats: int):
"""Run the performance test for the given code."""

def do_performance_test(
code_to_test: Union[str, dict[str, str], list[str]],
size_list: list[int],
repeats: int,
setup_codes: dict[str, str],
):
"""Generalized performance test runner."""
print(f"{'-' * 20} {inspect.stack()[1][3]} {'-' * 20}")

for array_size in array_sizes:
for size in size_list:
formatted_setup_codes = {key: code.format(size=size) for key, code in setup_codes.items()}
if isinstance(code_to_test, dict):
code_to_test_list = [code_to_test[variant].format(array_size=array_size) for variant in SETUP_CODES]
else:
code_to_test_list = [code_to_test.format(array_size=array_size)] * len(SETUP_CODES)
print(f"\n\tArray size: {array_size}\n")
setup_codes = [setup_code.format(array_size=array_size) for setup_code in SETUP_CODES.values()]
timings = _get_timings(setup_codes, code_to_test_list, repeats)

if code_to_test == "pass":
_print_timings(timings, list(SETUP_CODES.keys()), setup_codes)
code_to_test_list = [code_to_test[variant].format(size=size) for variant in setup_codes]
test_generator = zip(formatted_setup_codes.items(), code_to_test_list)
elif isinstance(code_to_test, list):
code_to_test_list = [code.format(size=size) for code in code_to_test]
test_generator = product(formatted_setup_codes.items(), code_to_test_list)
else:
_print_timings(timings, list(SETUP_CODES.keys()), code_to_test_list)
print()
test_generator = product(formatted_setup_codes.items(), [code_to_test.format(size=size)])

print(f"\n\tsize: {size}\n")

def do_graph_test(code_to_test: str | dict[str, str], graph_sizes: list[int], repeats: int):
"""Run the performance test for the given code."""
timings = _get_timings(test_generator, repeats=repeats)
_print_timings(timings)

print(f"{'-' * 20} {inspect.stack()[1][3]} {'-' * 20}")

for graph_size in graph_sizes:
if isinstance(code_to_test, dict):
code_to_test_list = [code_to_test[variant] for variant in GRAPH_SETUP_CODES]
else:
code_to_test_list = [code_to_test] * len(GRAPH_SETUP_CODES)
print(f"\n\tGraph size: {graph_size}\n")
setup_codes = [setup_code.format(graph_size=graph_size) for setup_code in GRAPH_SETUP_CODES.values()]
timings = _get_timings(setup_codes, code_to_test_list, repeats)

if code_to_test == "pass":
_print_graph_timings(timings, list(GRAPH_SETUP_CODES.keys()), setup_codes)
else:
_print_graph_timings(timings, list(GRAPH_SETUP_CODES.keys()), code_to_test_list)
print()


def _print_test_code(code: str | dict[str, str], repeats: int):
print(f"{'-' * 40}")
if isinstance(code, dict):
for variant, code_variant in code.items():
print(f"{variant}")
print(f"\t{code_variant} (x {repeats})")
return
print(f"{code} (x {repeats})")


def _print_graph_timings(timings: Generator, graph_types: list[str], code_list: list[str]):
for graph_type, timing, code in zip(graph_types, timings, code_list):
if ";" in code:
code = code.split(";")[-1]

code = code.replace("\n", " ").replace("\t", " ")
code = f"{graph_type}: " + code

if isinstance(timing, Exception):
print(f"\t\t{code.ljust(100)} | Not supported")
continue
print(f"\t\t{code.ljust(100)} | {sum(timing):.2f}s")


def _print_timings(timings: Generator, array_types: list[str], code_list: list[str]):
for array, timing, code in zip(array_types, timings, code_list):
if ";" in code:
code = code.split(";")[-1]

code = code.replace("\n", " ").replace("\t", " ")
array_name = f"{array}_array"
code = code.replace("input_array", array_name)
def _print_timings(timings: Generator):
for key, code, timing in timings:
code = code.split(";")[-1].replace("\n", " ").replace("\t", " ")
code = f"{key}: {code}"

if isinstance(timing, Exception):
print(f"\t\t{code.ljust(100)} | Not supported")
continue
print(f"\t\t{code.ljust(100)} | {sum(timing):.2f}s")


def _get_timings(setup_codes: list[str], test_codes: list[str], repeats: int):
def _get_timings(test_generator, repeats: int):
"""Return a generator with the timings for each array type."""
for setup_code, test_code in zip(setup_codes, test_codes):
for (key, setup_code), test_code in test_generator:
if test_code == "pass":
yield timeit.repeat(setup_code, number=repeats)
yield key, "intialise", timeit.repeat(setup_code, number=repeats)
else:
try:
yield timeit.repeat(test_code, setup_code, number=repeats)
yield key, test_code, timeit.repeat(test_code, setup_code, number=repeats)
# pylint: disable=broad-exception-caught
except Exception as error: # noqa
yield error
yield key, test_code, error
Loading

0 comments on commit 676fd30

Please sign in to comment.