Skip to content

Commit b14330c

Browse files
authored
Merge pull request #1369 from PowerGridModel/pgm/feature/source-sk-updatable
Allow source short circuit power to be updated for batch calculation
2 parents eb01480 + cc6b468 commit b14330c

18 files changed

Lines changed: 1153 additions & 42 deletions

File tree

code_generation/data/attribute_classes/update.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
"data_type": "double",
8888
"names": ["u_ref", "u_ref_angle"],
8989
"description": "reference voltage"
90+
},
91+
{
92+
"data_type": "double",
93+
"names": ["sk", "rx_ratio", "z01_ratio"],
94+
"description": "short circuit capacity"
9095
}
9196
]
9297
},

docs/user_manual/components.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,9 @@ The impedance is specified by convention as short circuit power.
614614
|---------------|-----------|------------------|----------------------------------------------------|:----------------------------:|:--------:|:------------:|
615615
| `u_ref` | `double` | - | reference voltage in per-unit | ✨ only for power flow | ✔ | `> 0` |
616616
| `u_ref_angle` | `double` | rad | reference voltage angle | ❌ default `0.0` | ✔ | |
617-
| `sk` | `double` | volt-ampere (VA) | short circuit power | ❌ default `1e10` | ❌ | `> 0` |
618-
| `rx_ratio` | `double` | - | R to X ratio | ❌ default `0.1` | ❌ | `>= 0` |
619-
| `z01_ratio` | `double` | - | zero-sequence to positive sequence impedance ratio | ❌ default `1.0` | ❌ | `> 0` |
617+
| `sk` | `double` | volt-ampere (VA) | short circuit power | ❌ default `1e10` | ✔ | `> 0` |
618+
| `rx_ratio` | `double` | - | R to X ratio | ❌ default `0.1` | ✔ | `>= 0` |
619+
| `z01_ratio` | `double` | - | zero-sequence to positive sequence impedance ratio | ❌ default `1.0` | ✔ | `> 0` |
620620

621621
#### Electric Model
622622

power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/update.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,16 @@ struct get_attributes_list<LoadGenUpdate<sym_type>> {
105105

106106
template<>
107107
struct get_attributes_list<SourceUpdate> {
108-
static constexpr std::array<MetaAttribute, 4> value{
108+
static constexpr std::array<MetaAttribute, 7> value{
109109
// all attributes including base class
110110

111111
meta_data_gen::get_meta_attribute<&SourceUpdate::id>(offsetof(SourceUpdate, id), "id"),
112112
meta_data_gen::get_meta_attribute<&SourceUpdate::status>(offsetof(SourceUpdate, status), "status"),
113113
meta_data_gen::get_meta_attribute<&SourceUpdate::u_ref>(offsetof(SourceUpdate, u_ref), "u_ref"),
114114
meta_data_gen::get_meta_attribute<&SourceUpdate::u_ref_angle>(offsetof(SourceUpdate, u_ref_angle), "u_ref_angle"),
115+
meta_data_gen::get_meta_attribute<&SourceUpdate::sk>(offsetof(SourceUpdate, sk), "sk"),
116+
meta_data_gen::get_meta_attribute<&SourceUpdate::rx_ratio>(offsetof(SourceUpdate, rx_ratio), "rx_ratio"),
117+
meta_data_gen::get_meta_attribute<&SourceUpdate::z01_ratio>(offsetof(SourceUpdate, z01_ratio), "z01_ratio"),
115118
};
116119
};
117120

power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/update.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ struct SourceUpdate {
104104
IntS status{na_IntS}; // whether the appliance is connected
105105
double u_ref{nan}; // reference voltage
106106
double u_ref_angle{nan}; // reference voltage
107+
double sk{nan}; // short circuit capacity
108+
double rx_ratio{nan}; // short circuit capacity
109+
double z01_ratio{nan}; // short circuit capacity
107110

108111
// implicit conversions to BaseUpdate
109112
operator BaseUpdate&() { return reinterpret_cast<BaseUpdate&>(*this); }

power_grid_model_c/power_grid_model/include/power_grid_model/component/source.hpp

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,22 @@ class Source : public Appliance {
3232
explicit Source(SourceInput const& source_input, double u)
3333
: Appliance{source_input, u},
3434
u_ref_{source_input.u_ref},
35-
u_ref_angle_{is_nan(source_input.u_ref_angle) ? 0.0 : source_input.u_ref_angle} {
36-
double const sk{is_nan(source_input.sk) ? default_source_sk : source_input.sk};
37-
double const rx_ratio{is_nan(source_input.rx_ratio) ? default_source_rx_ratio : source_input.rx_ratio};
38-
double const z01_ratio{is_nan(source_input.z01_ratio) ? default_source_z01_ratio : source_input.z01_ratio};
39-
calculate_y_ref(sk, rx_ratio, z01_ratio);
40-
}
41-
42-
// calculate y1 y0 ref
43-
void calculate_y_ref(double sk, double rx_ratio, double z01_ratio) {
44-
double const z_abs = base_power_3p / sk; // s_pu = s/base_s, z = u^2/s = 1/s = base_s/s_pu
45-
double const x1 = z_abs / sqrt(rx_ratio * rx_ratio + 1.0);
46-
double const r1 = x1 * rx_ratio;
47-
y1_ref_ = 1.0 / DoubleComplex{r1, x1};
48-
y0_ref_ = y1_ref_ / z01_ratio;
49-
}
35+
u_ref_angle_{is_nan(source_input.u_ref_angle) ? 0.0 : source_input.u_ref_angle},
36+
sk_{is_nan(source_input.sk) ? default_source_sk : source_input.sk},
37+
rx_ratio_{is_nan(source_input.rx_ratio) ? default_source_rx_ratio : source_input.rx_ratio},
38+
z01_ratio_{is_nan(source_input.z01_ratio) ? default_source_z01_ratio : source_input.z01_ratio} {}
5039

5140
template <symmetry_tag sym> SourceCalcParam math_param() const {
52-
// internal element_admittance
53-
SourceCalcParam param;
54-
param.y0 = y0_ref_;
55-
param.y1 = y1_ref_;
56-
return param;
41+
// calculate y1 y0 ref
42+
double const z_abs = base_power_3p / sk_;
43+
double const x1 = z_abs / sqrt(rx_ratio_ * rx_ratio_ + 1.0);
44+
double const r1 = x1 * rx_ratio_;
45+
DoubleComplex const y1_ref = 1.0 / DoubleComplex{r1, x1};
46+
DoubleComplex const y0_ref = y1_ref / z01_ratio_;
47+
return SourceCalcParam{.y1 = y1_ref, .y0 = y0_ref};
5748
}
5849

59-
// setter
50+
// setter for u_ref
6051
bool set_u_ref(double new_u_ref, double new_u_ref_angle) {
6152
bool changed = false;
6253
if (!is_nan(new_u_ref)) {
@@ -96,10 +87,13 @@ class Source : public Appliance {
9687
UpdateChange update(SourceUpdate const& update_data) {
9788
assert(update_data.id == this->id() || is_nan(update_data.id));
9889
bool const topo_changed = set_status(update_data.status);
99-
bool const param_changed = set_u_ref(update_data.u_ref, update_data.u_ref_angle);
90+
set_u_ref(update_data.u_ref, update_data.u_ref_angle);
91+
bool const param_changed_impedance =
92+
set_sk_rx_ratio_z01_ratio(update_data.sk, update_data.rx_ratio, update_data.z01_ratio);
10093
// change source connection will change both topo and param
101-
// change u ref will change param
102-
return {.topo = topo_changed, .param = param_changed || topo_changed};
94+
// change u ref will NOT change param
95+
// change sk/rx_ratio/z01_ratio will change param
96+
return {.topo = topo_changed, .param = param_changed_impedance || topo_changed};
10397
}
10498

10599
SourceUpdate inverse(SourceUpdate update_data) const {
@@ -108,6 +102,9 @@ class Source : public Appliance {
108102
set_if_not_nan(update_data.status, status_to_int(this->status()));
109103
set_if_not_nan(update_data.u_ref, u_ref_);
110104
set_if_not_nan(update_data.u_ref_angle, u_ref_angle_);
105+
set_if_not_nan(update_data.sk, sk_);
106+
set_if_not_nan(update_data.rx_ratio, rx_ratio_);
107+
set_if_not_nan(update_data.z01_ratio, z01_ratio_);
111108

112109
return update_data;
113110
}
@@ -117,9 +114,27 @@ class Source : public Appliance {
117114
private:
118115
double u_ref_;
119116
double u_ref_angle_;
120-
// positive and zero sequence ref
121-
DoubleComplex y1_ref_;
122-
DoubleComplex y0_ref_;
117+
// source short circuit power
118+
double sk_;
119+
double rx_ratio_;
120+
double z01_ratio_;
121+
122+
bool set_sk_rx_ratio_z01_ratio(double new_sk, double new_rx_ratio, double new_z01_ratio) {
123+
bool changed = false;
124+
if (!is_nan(new_sk)) {
125+
sk_ = new_sk;
126+
changed = true;
127+
}
128+
if (!is_nan(new_rx_ratio)) {
129+
rx_ratio_ = new_rx_ratio;
130+
changed = true;
131+
}
132+
if (!is_nan(new_z01_ratio)) {
133+
z01_ratio_ = new_z01_ratio;
134+
changed = true;
135+
}
136+
return changed;
137+
}
123138

124139
double injection_direction() const final { return 1.0; }
125140
};

power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,6 @@ template <symmetry_tag sym> class YBus {
378378
return 0 <= idx && idx < std::ssize(math_model_param_.source_param);
379379
}));
380380

381-
assert(
382-
std::ranges::equal(math_model_param_incrmt.source_param,
383-
math_model_param_incrmt.source_param_to_change |
384-
std::views::transform([&](auto idx) { return math_model_param_.source_param[idx]; }),
385-
[](auto const& lhs, auto const& rhs) { return lhs.y1 == rhs.y1 && lhs.y0 == rhs.y0; }) &&
386-
"updateable source params currently do not affect y1 and y0, so the new values should be the same as old "
387-
"values");
388-
389381
for (auto const& [idx_to_change, params] :
390382
std::views::zip(math_model_param_incrmt.branch_param_to_change, math_model_param_incrmt.branch_param)) {
391383
math_model_param_.branch_param[idx_to_change] = params;
@@ -394,6 +386,10 @@ template <symmetry_tag sym> class YBus {
394386
std::views::zip(math_model_param_incrmt.shunt_param_to_change, math_model_param_incrmt.shunt_param)) {
395387
math_model_param_.shunt_param[idx_to_change] = params;
396388
}
389+
for (auto const& [idx_to_change, params] :
390+
std::views::zip(math_model_param_incrmt.source_param_to_change, math_model_param_incrmt.source_param)) {
391+
math_model_param_.source_param[idx_to_change] = params;
392+
}
397393

398394
// process and update affected entries
399395
update_admittance_entries(get_affected_admittance_entries(math_model_param_incrmt));

power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_id;
884884
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_status;
885885
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_u_ref;
886886
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_u_ref_angle;
887+
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_sk;
888+
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_rx_ratio;
889+
PGM_API extern PGM_MetaAttribute const* const PGM_def_update_source_z01_ratio;
887890
// component sym_voltage_sensor
888891
PGM_API extern PGM_MetaComponent const* const PGM_def_update_sym_voltage_sensor;
889892
// attributes of update sym_voltage_sensor

power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,9 @@ PGM_MetaAttribute const* const PGM_def_update_source_id = PGM_meta_get_attribute
873873
PGM_MetaAttribute const* const PGM_def_update_source_status = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "status");
874874
PGM_MetaAttribute const* const PGM_def_update_source_u_ref = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "u_ref");
875875
PGM_MetaAttribute const* const PGM_def_update_source_u_ref_angle = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "u_ref_angle");
876+
PGM_MetaAttribute const* const PGM_def_update_source_sk = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "sk");
877+
PGM_MetaAttribute const* const PGM_def_update_source_rx_ratio = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "rx_ratio");
878+
PGM_MetaAttribute const* const PGM_def_update_source_z01_ratio = PGM_meta_get_attribute_by_name(nullptr, "update", "source", "z01_ratio");
876879
// component sym_voltage_sensor
877880
PGM_MetaComponent const* const PGM_def_update_sym_voltage_sensor = PGM_meta_get_component_by_name(nullptr, "update", "sym_voltage_sensor");
878881
// attributes of update sym_voltage_sensor

tests/cpp_unit_tests/test_source.cpp

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,63 @@ TEST_CASE("Test source") {
191191
SUBCASE("test update") {
192192
auto changed = source.update(SourceUpdate{.id = 1, .status = 1, .u_ref = 1.05, .u_ref_angle = nan});
193193
CHECK(!changed.topo);
194-
CHECK(changed.param);
194+
CHECK(!changed.param);
195195
changed = source.update(SourceUpdate{.id = 1, .status = 0, .u_ref = 1.05, .u_ref_angle = nan});
196196
CHECK(changed.topo);
197197
CHECK(changed.param);
198198
changed = source.update(SourceUpdate{.id = 1, .status = 0, .u_ref = nan, .u_ref_angle = nan});
199199
CHECK(!changed.topo);
200200
CHECK(!changed.param);
201+
202+
// test updating sk, rx_ratio, z01_ratio (status remains 0)
203+
changed = source.update(SourceUpdate{.id = 1,
204+
.status = na_IntS,
205+
.u_ref = nan,
206+
.u_ref_angle = nan,
207+
.sk = 20e6,
208+
.rx_ratio = nan,
209+
.z01_ratio = nan});
210+
CHECK(!changed.topo);
211+
CHECK(changed.param);
212+
213+
// verify the new impedance affects math_param
214+
DoubleComplex const y_ref_sym_updated = source.math_param<symmetric_t>().template y_ref<symmetric_t>();
215+
CHECK(cabs(y_ref_sym_updated - y_ref_sym) > numerical_tolerance); // should be different
216+
217+
changed = source.update(SourceUpdate{.id = 1,
218+
.status = na_IntS,
219+
.u_ref = nan,
220+
.u_ref_angle = nan,
221+
.sk = nan,
222+
.rx_ratio = 0.2,
223+
.z01_ratio = nan});
224+
CHECK(!changed.topo);
225+
CHECK(changed.param);
226+
227+
changed = source.update(SourceUpdate{.id = 1,
228+
.status = na_IntS,
229+
.u_ref = nan,
230+
.u_ref_angle = nan,
231+
.sk = nan,
232+
.rx_ratio = nan,
233+
.z01_ratio = 4.0});
234+
CHECK(!changed.topo);
235+
CHECK(changed.param);
236+
237+
changed = source.update(SourceUpdate{.id = 1,
238+
.status = na_IntS,
239+
.u_ref = nan,
240+
.u_ref_angle = nan,
241+
.sk = nan,
242+
.rx_ratio = nan,
243+
.z01_ratio = nan});
244+
CHECK(!changed.topo);
245+
CHECK(!changed.param);
201246
}
202247

203248
SUBCASE("Update inverse") {
204-
SourceUpdate source_update{.id = 1, .status = na_IntS, .u_ref = nan, .u_ref_angle = nan};
249+
SourceUpdate source_update{
250+
.id = 1, .status = na_IntS, .u_ref = nan, .u_ref_angle = nan, .sk = nan, .rx_ratio = nan, .z01_ratio = nan};
205251
auto expected = source_update;
206252

207253
SUBCASE("Identical") {
@@ -225,13 +271,37 @@ TEST_CASE("Test source") {
225271
expected.u_ref_angle = nan;
226272
}
227273

274+
SUBCASE("sk") {
275+
SUBCASE("same") { source_update.sk = sk; }
276+
SUBCASE("different") { source_update.sk = 20e6; }
277+
expected.sk = sk;
278+
}
279+
280+
SUBCASE("rx_ratio") {
281+
SUBCASE("same") { source_update.rx_ratio = rx_ratio; }
282+
SUBCASE("different") { source_update.rx_ratio = 0.2; }
283+
expected.rx_ratio = rx_ratio;
284+
}
285+
286+
SUBCASE("z01_ratio") {
287+
SUBCASE("same") { source_update.z01_ratio = z01_ratio; }
288+
SUBCASE("different") { source_update.z01_ratio = 4.0; }
289+
expected.z01_ratio = z01_ratio;
290+
}
291+
228292
SUBCASE("multiple") {
229293
source_update.status = IntS{0};
230294
source_update.u_ref = 0.0;
231295
source_update.u_ref_angle = 0.1;
296+
source_update.sk = 20e6;
297+
source_update.rx_ratio = 0.2;
298+
source_update.z01_ratio = 4.0;
232299
expected.status = status_to_int(source.status());
233300
expected.u_ref = u_input;
234301
expected.u_ref_angle = nan;
302+
expected.sk = sk;
303+
expected.rx_ratio = rx_ratio;
304+
expected.z01_ratio = z01_ratio;
235305
}
236306

237307
auto const inv = source.inverse(source_update);
@@ -240,6 +310,9 @@ TEST_CASE("Test source") {
240310
CHECK(inv.status == expected.status);
241311
check_nan_preserving_equality(inv.u_ref, expected.u_ref);
242312
check_nan_preserving_equality(inv.u_ref_angle, expected.u_ref_angle);
313+
check_nan_preserving_equality(inv.sk, expected.sk);
314+
check_nan_preserving_equality(inv.rx_ratio, expected.rx_ratio);
315+
check_nan_preserving_equality(inv.z01_ratio, expected.z01_ratio);
243316
}
244317
}
245318

0 commit comments

Comments
 (0)