Skip to content

Commit 2b17479

Browse files
Merge remote-tracking branch 'origin/main' into feature/more-ruff-checks
2 parents 17fd1f4 + a70feb0 commit 2b17479

File tree

53 files changed

+1203
-260
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1203
-260
lines changed

.github/workflows/sonar.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ jobs:
4646
uses: actions/setup-python@v5
4747
with:
4848
python-version: "3.12"
49-
- name: Install sonar-scanner and build-wrapper
50-
uses: SonarSource/sonarcloud-github-c-cpp@v3
49+
- name: Install build-wrapper
50+
uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5
5151

5252
- name: Python test and coverage
5353
run: |
@@ -70,11 +70,13 @@ jobs:
7070
# remove branch hits count, since it does not make sense in heavy C++ templates
7171
sed -i -r "s/\s*branchesToCover\s*=\s*\"[0-9]+\"\s+coveredBranches\s*=\s*\"[0-9]+\"//g" cpp_coverage.xml
7272
73-
- name: Run sonar-scanner
73+
- name: SonarQube Scan
7474
# only run sonar server in push event or pull request event from own repo
75-
if: ${{ (github.event_name == 'push') || (github.event.pull_request.head.repo.owner.login == 'PowerGridModel') }}
75+
if: ${{ (github.event_name == 'push') || (github.event.pull_request.head.repo.owner.login == 'PowerGridModel') }}
7676
env:
7777
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7878
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
79-
run: |
80-
sonar-scanner --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"
79+
uses: SonarSource/sonarqube-scan-action@v5
80+
with:
81+
args: >
82+
--define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"

docs/examples/Transformer Examples.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@
386386
"three_winding_transformer[\"winding_2\"] = [1]\n",
387387
"three_winding_transformer[\"winding_3\"] = [1]\n",
388388
"three_winding_transformer[\"clock_12\"] = [5]\n",
389-
"three_winding_transformer[\"clock_13\"] = [5]\n",
389+
"three_winding_transformer[\"clock_13\"] = [-7] # supports periodic input\n",
390390
"three_winding_transformer[\"tap_side\"] = [0]\n",
391391
"three_winding_transformer[\"tap_pos\"] = [0]\n",
392392
"three_winding_transformer[\"tap_min\"] = [-10]\n",

docs/user_manual/calculations.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ state estimation calculation in `power-grid-model`.
147147
- If no voltage phasor sensors are available, then both the following conditions shall be satisfied:
148148
- There are no global angle current sensors.
149149
- `n_unique_power_or_current_sensor >= n_bus - 1`.
150-
- Otherwise (if there are voltage phasor sensors available), the following condition shall be satisfied:
151-
- `n_unique_power_or_current_sensor + n_voltage_sensor_with_phasor >= n_bus`
150+
- Otherwise (if there are voltage phasor sensors available, one will be reserved as reference),
151+
the following condition shall be satisfied:
152+
- `n_unique_power_or_current_sensor + n_voltage_sensor_with_phasor - 1 >= n_bus - 1`
152153

153154
`n_unique_power_or_current_sensor` can be calculated as sum of following:
154155

docs/user_manual/components.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ An example of usage of transformer is given in [Transformer Examples](../example
196196
| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` |
197197
| `winding_from` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | from-side winding type | &#10004; | &#10060; | |
198198
| `winding_to` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | to-side winding type | &#10004; | &#10060; | |
199-
| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | &#10004; | &#10060; | `>= 0` and `<= 12` |
199+
| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | &#10004; | &#10060; | `>= -12` and `<= 12` |
200200
| `tap_side` | {py:class}`BranchSide <power_grid_model.enum.BranchSide>` | - | side of tap changer | &#10004; | &#10060; | |
201201
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10060; default `tap_nom`, if no `tap_nom` default `0` | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
202202
| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | &#10004; | &#10060; | |
@@ -514,8 +514,8 @@ An example of usage of three-winding transformer is given in
514514
| `winding_1` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | side 1 winding type | &#10004; | &#10060; | |
515515
| `winding_2` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | side 2 winding type | &#10004; | &#10060; | |
516516
| `winding_3` | {py:class}`WindingType <power_grid_model.enum.WindingType>` | - | side 3 winding type | &#10004; | &#10060; | |
517-
| `clock_12` | `int8_t` | - | clock number of phase shift across side 1-2, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= 0` and `<= 12` |
518-
| `clock_13` | `int8_t` | - | clock number of phase shift across side 1-3, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= 0` and `<= 12` |
517+
| `clock_12` | `int8_t` | - | clock number of phase shift across side 1-2, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= -12` and `<= 12` |
518+
| `clock_13` | `int8_t` | - | clock number of phase shift across side 1-3, odd number is only allowed for Dy(n) or Y(N)d configuration. | &#10004; | &#10060; | `>= -12` and `<= 12` |
519519
| `tap_side` | {py:class}`Branch3Side <power_grid_model.enum.Branch3Side>` | - | side of tap changer | &#10004; | &#10060; | `side_1` or `side_2` or `side_3` |
520520
| `tap_pos` | `int8_t` | - | current position of tap changer | &#10060; default `tap_nom`, if no `tap_nom` default `0` | &#10004; | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` |
521521
| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | &#10004; | &#10060; | |

power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#pragma once
66

7+
#include <cmath>
78
#include <complex>
89
#include <cstddef>
910
#include <cstdint>
@@ -108,4 +109,21 @@ struct IncludeAll {
108109
};
109110
constexpr IncludeAll include_all{};
110111

112+
// function to handle periodic mapping
113+
template <typename T> constexpr T map_to_cyclic_range(T value, T period) {
114+
static_assert(std::is_arithmetic_v<T>, "T must be an arithmetic type (integral or floating-point)");
115+
if constexpr (std::is_integral_v<T>) {
116+
return static_cast<T>((value % period + period) % period);
117+
} else {
118+
if (std::is_constant_evaluated()) {
119+
T quotient = value / period;
120+
Idx const floored_quotient =
121+
(quotient >= T{0}) ? static_cast<Idx>(quotient) : static_cast<Idx>(quotient) - 1;
122+
T result = value - static_cast<T>(floored_quotient) * period;
123+
return result;
124+
}
125+
return std::fmod(std::fmod(value, period) + period, period);
126+
}
127+
}
128+
111129
} // namespace power_grid_model

power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class SparseMatrixError : public PowerGridError {
9696
: PowerGridError{"Sparse matrix error, possibly singular matrix!\n"
9797
"If you get this error from state estimation, "
9898
"it might mean the system is not fully observable, i.e. not enough measurements.\n"
99-
"It might also mean that you are running into a corner case where PGM cannot resolve yet."
99+
"It might also mean that you are running into a corner case where PGM cannot resolve yet.\n"
100100
"See https://github.com/PowerGridModel/power-grid-model/issues/864."} {}
101101
};
102102

power_grid_model_c/power_grid_model/include/power_grid_model/component/three_winding_transformer.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ class ThreeWindingTransformer : public Branch3 {
9393
throw InvalidTransformerClock{id(), clock_13_};
9494
}
9595

96-
// set clock to zero if it is 12
97-
clock_12_ = static_cast<IntS>(clock_12_ % 12);
98-
clock_13_ = static_cast<IntS>(clock_13_ % 12);
96+
// handle periodic clock input -> in range [0, 11]
97+
clock_12_ = map_to_cyclic_range(clock_12_, IntS{12});
98+
clock_13_ = map_to_cyclic_range(clock_13_, IntS{12});
9999
// check tap bounds
100100
tap_pos_ = tap_limit(tap_pos_);
101101
}
@@ -119,6 +119,8 @@ class ThreeWindingTransformer : public Branch3 {
119119
constexpr IntS tap_min() const { return tap_min_; }
120120
constexpr IntS tap_max() const { return tap_max_; }
121121
constexpr IntS tap_nom() const { return tap_nom_; }
122+
constexpr IntS clock_12() const { return clock_12_; }
123+
constexpr IntS clock_13() const { return clock_13_; }
122124

123125
// setter
124126
constexpr bool set_tap(IntS new_tap) {

power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ class Transformer : public Branch {
6363
throw InvalidTransformerClock{id(), clock_};
6464
}
6565

66-
// set clock to zero if it is 12
67-
clock_ = static_cast<IntS>(clock_ % 12);
66+
// handle periodic clock input -> in range [0, 11]
67+
clock_ = map_to_cyclic_range(clock_, IntS{12});
6868
// check tap bounds
6969
tap_pos_ = tap_limit(tap_pos_);
7070
}
@@ -82,6 +82,7 @@ class Transformer : public Branch {
8282
constexpr IntS tap_min() const { return tap_min_; }
8383
constexpr IntS tap_max() const { return tap_max_; }
8484
constexpr IntS tap_nom() const { return tap_nom_; }
85+
constexpr IntS clock() const { return clock_; }
8586

8687
// setter
8788
constexpr bool set_tap(IntS new_tap) {

power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer_utils.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,14 @@ constexpr double tap_adjust_impedance(double tap_pos, double tap_min, double tap
4545
constexpr bool is_valid_clock(IntS clock, WindingType winding_from, WindingType winding_to) {
4646
using enum WindingType;
4747

48-
bool const clock_in_range = 0 <= clock && clock <= 12;
4948
bool const clock_is_even = (clock % 2) == 0;
5049

5150
bool const is_from_wye = winding_from == wye || winding_from == wye_n;
5251
bool const is_to_wye = winding_to == wye || winding_to == wye_n;
5352

5453
// even clock number is only possible when both sides are wye winding or both sides aren't
5554
// and conversely for odd clock number
56-
bool const correct_clock_winding = (clock_is_even == (is_from_wye == is_to_wye));
57-
58-
return clock_in_range && correct_clock_winding;
55+
return (clock_is_even == (is_from_wye == is_to_wye));
5956
}
6057

6158
// add tap

0 commit comments

Comments
 (0)