Skip to content

Commit 068bf8e

Browse files
authored
Merge branch 'main' into feature/links-part-3
2 parents a9940b8 + 2d3b2c4 commit 068bf8e

20 files changed

Lines changed: 1238 additions & 97 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/dataset.hpp

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,22 @@
1010
#include "meta_data.hpp"
1111

1212
#include "../common/common.hpp"
13+
#include "../common/counting_iterator.hpp"
1314
#include "../common/exception.hpp"
1415
#include "../common/iterator_facade.hpp"
16+
#include "../common/typing.hpp"
1517

1618
#include <algorithm>
1719
#include <cassert>
1820
#include <concepts>
1921
#include <cstddef>
22+
#include <iterator>
2023
#include <ranges>
2124
#include <span>
2225
#include <string>
2326
#include <string_view>
2427
#include <type_traits>
28+
#include <utility>
2529
#include <vector>
2630

2731
namespace power_grid_model {
@@ -216,6 +220,8 @@ template <dataset_type_tag dataset_type_> class Dataset {
216220
std::span<Indptr> indptr{};
217221
};
218222

223+
template <class StructType> using SpanRange = std::span<StructType>;
224+
219225
template <class StructType>
220226
using RangeObject = std::conditional_t<is_data_mutable_v<dataset_type>, mutable_range_object<StructType>,
221227
const_range_object<StructType>>;
@@ -452,7 +458,7 @@ template <dataset_type_tag dataset_type_> class Dataset {
452458
// get buffer by component type
453459
template <class type_getter, class ComponentType,
454460
class StructType = DataStruct<typename type_getter::template type<ComponentType>>>
455-
std::span<StructType> get_buffer_span(Idx scenario = invalid_index) const {
461+
SpanRange<StructType> get_buffer_span(Idx scenario = invalid_index) const {
456462
assert(scenario < batch_size());
457463

458464
if (!is_batch() && scenario > 0) {
@@ -476,27 +482,17 @@ template <dataset_type_tag dataset_type_> class Dataset {
476482
return get_columnar_buffer_span_impl<StructType>(scenario, idx);
477483
}
478484

479-
// get buffer by component type for all scenarios in vector span
485+
// get buffer by component type for all non-empty scenarios in vector span
480486
template <class type_getter, class ComponentType,
481487
class StructType = DataStruct<typename type_getter::template type<ComponentType>>>
482-
std::vector<std::span<StructType>> get_buffer_span_all_scenarios() const {
483-
Idx const idx = find_component(ComponentType::name, false);
484-
std::vector<std::span<StructType>> result(batch_size());
485-
for (Idx scenario{}; scenario != batch_size(); scenario++) {
486-
result[scenario] = get_buffer_span_impl<StructType>(scenario, idx);
487-
}
488-
return result;
488+
std::vector<SpanRange<StructType>> get_buffer_span_all_scenarios() const {
489+
return get_buffer_span_all_scenarios_impl<type_getter, ComponentType, SpanRange>();
489490
}
490491

491492
template <class type_getter, class ComponentType,
492493
class StructType = DataStruct<typename type_getter::template type<ComponentType>>>
493494
std::vector<RangeObject<StructType>> get_columnar_buffer_span_all_scenarios() const {
494-
Idx const idx = find_component(ComponentType::name, false);
495-
std::vector<RangeObject<StructType>> result(batch_size());
496-
for (Idx scenario{}; scenario != batch_size(); scenario++) {
497-
result[scenario] = get_columnar_buffer_span_impl<StructType>(scenario, idx);
498-
}
499-
return result;
495+
return get_buffer_span_all_scenarios_impl<type_getter, ComponentType, RangeObject>();
500496
}
501497

502498
// get individual dataset from batch
@@ -559,7 +555,7 @@ template <dataset_type_tag dataset_type_> class Dataset {
559555

560556
template <class type_getter, class ComponentType, typename Func,
561557
class StructType = DataStruct<typename type_getter::template type<ComponentType>>>
562-
requires std::invocable<Func, std::span<StructType>> && std::invocable<Func, RangeObject<StructType>>
558+
requires std::invocable<Func, SpanRange<StructType>> && std::invocable<Func, RangeObject<StructType>>
563559
auto for_each_component(Func&& func, Idx scenario = invalid_index) const {
564560
if (is_columnar(ComponentType::name)) {
565561
return std::forward<Func>(func)(get_columnar_buffer_span<type_getter, ComponentType, StructType>(scenario));
@@ -659,31 +655,53 @@ template <dataset_type_tag dataset_type_> class Dataset {
659655
std::begin(total_range) + info.elements_per_scenario * (scenario + 1)};
660656
}
661657

662-
// get non-empty row buffer
663-
template <class StructType> std::span<StructType> get_buffer_span_impl(Idx scenario, Idx component_idx) const {
658+
template <typename StructType, template <typename> typename RangeType>
659+
requires std::ranges::view<RangeType<StructType>> &&
660+
(std::same_as<RangeType<StructType>, SpanRange<StructType>> ||
661+
std::same_as<RangeType<StructType>, RangeObject<StructType>>)
662+
auto get_buffer_view_impl(Idx scenario, Idx component_idx) const {
663+
using RangeType_ = RangeType<StructType>;
664+
664665
// return empty span if the component does not exist
665666
if (component_idx < 0) {
666-
return {};
667+
return RangeType_{};
667668
}
668669
// return span based on uniform or non-uniform buffer
669670
ComponentInfo const& info = dataset_info_.component_info[component_idx];
670671
Buffer const& buffer = buffers_[component_idx];
671-
auto const ptr = reinterpret_cast<StructType*>(buffer.data);
672-
return get_span_impl(std::span<StructType>{ptr, ptr + info.total_elements}, scenario, buffer, info);
672+
673+
if constexpr (std::same_as<RangeType_, SpanRange<StructType>>) {
674+
assert(is_row_based(buffer) || info.total_elements == 0);
675+
auto const ptr = reinterpret_cast<StructType*>(buffer.data);
676+
return get_span_impl(RangeType_{ptr, ptr + info.total_elements}, scenario, buffer, info);
677+
} else if constexpr (std::same_as<RangeType_, RangeObject<StructType>>) {
678+
assert(is_columnar(buffer));
679+
return get_span_impl(RangeType_{info.total_elements, buffer.attributes}, scenario, buffer, info);
680+
} else {
681+
static_assert(false, "only span and RangeObject are supported");
682+
}
683+
}
684+
685+
// get non-empty row buffer
686+
template <class StructType> SpanRange<StructType> get_buffer_span_impl(Idx scenario, Idx component_idx) const {
687+
return get_buffer_view_impl<StructType, SpanRange>(scenario, component_idx);
673688
}
674689

675690
// get non-empty columnar buffer
676691
template <class StructType>
677692
RangeObject<StructType> get_columnar_buffer_span_impl(Idx scenario, Idx component_idx) const {
678-
// return empty span if the component does not exist
679-
if (component_idx < 0) {
680-
return {};
681-
}
682-
// return span based on uniform or non-uniform buffer
683-
ComponentInfo const& info = dataset_info_.component_info[component_idx];
684-
Buffer const& buffer = buffers_[component_idx];
685-
assert(is_columnar(buffer));
686-
return get_span_impl(RangeObject<StructType>{info.total_elements, buffer.attributes}, scenario, buffer, info);
693+
return get_buffer_view_impl<StructType, RangeObject>(scenario, component_idx);
694+
}
695+
696+
template <class type_getter, class ComponentType, template <typename> typename RangeType,
697+
typename StructType = DataStruct<typename type_getter::template type<ComponentType>>>
698+
requires std::ranges::view<RangeType<StructType>>
699+
std::vector<RangeType<StructType>> get_buffer_span_all_scenarios_impl() const {
700+
Idx const component_idx = find_component(ComponentType::name, false);
701+
return IdxRange{batch_size()} | std::views::transform([this, component_idx](Idx scenario) {
702+
return get_buffer_view_impl<StructType, RangeType>(scenario, component_idx);
703+
}) |
704+
std::ranges::to<std::vector>();
687705
}
688706
};
689707

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
};

0 commit comments

Comments
 (0)