Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8085e5b
start slice dataset
TonyXiang8787 Nov 10, 2025
73d85c5
add slice scenario
TonyXiang8787 Nov 10, 2025
234f38d
Merge branch 'main' into experimental/multi-dimension-batch
TonyXiang8787 Nov 10, 2025
be44d80
batch dimension
TonyXiang8787 Nov 10, 2025
1fd7ed3
calculation implementation
TonyXiang8787 Nov 10, 2025
45f4d72
error handling still needs to be done
TonyXiang8787 Nov 10, 2025
06cb330
error handling
TonyXiang8787 Nov 10, 2025
a4fc01e
add batch dimensions
TonyXiang8787 Nov 10, 2025
118655f
batch dimension
TonyXiang8787 Nov 10, 2025
3b41f28
start test
TonyXiang8787 Nov 10, 2025
d88db97
start test
TonyXiang8787 Nov 10, 2025
1b1190d
api will not work as intended
TonyXiang8787 Nov 10, 2025
21c31c5
api will not work as intended
TonyXiang8787 Nov 10, 2025
6e8c081
adjust md dataset
TonyXiang8787 Nov 11, 2025
0b989b4
add dataset
TonyXiang8787 Nov 11, 2025
14b4039
crash yet
TonyXiang8787 Nov 11, 2025
3338881
fix bounds checking
TonyXiang8787 Nov 11, 2025
01c86a9
remove span
TonyXiang8787 Nov 11, 2025
7786b0c
fix clang tidy
TonyXiang8787 Nov 11, 2025
5a3f394
format|
TonyXiang8787 Nov 11, 2025
2650968
[skip ci] add cfunc in python
TonyXiang8787 Nov 11, 2025
9aaa6bd
force nullptr
TonyXiang8787 Nov 11, 2025
e4aa439
add options
TonyXiang8787 Nov 11, 2025
237681f
proxy for multidimensional in python
TonyXiang8787 Nov 11, 2025
b602f2e
modify main calculate input
TonyXiang8787 Nov 11, 2025
3e79237
type annotation
TonyXiang8787 Nov 11, 2025
8d8d80c
[skip ci] not working yet
TonyXiang8787 Nov 11, 2025
61cfd57
fix dimensions
TonyXiang8787 Nov 11, 2025
a1331ba
fix mypy
TonyXiang8787 Nov 12, 2025
36707d9
Merge branch 'main' into experimental/multi-dimension-batch
TonyXiang8787 Nov 23, 2025
9c27e6e
empty slice
TonyXiang8787 Nov 25, 2025
bce908e
Merge branch 'main' into experimental/multi-dimension-batch
TonyXiang8787 Nov 25, 2025
7faa6c1
begin next
TonyXiang8787 Nov 25, 2025
c4b854e
revert api change
TonyXiang8787 Nov 25, 2025
cb67ae3
model calculate for chaining
TonyXiang8787 Nov 25, 2025
a7352f2
add dataset chaining
TonyXiang8787 Nov 25, 2025
b3c8901
revert cpp interface
TonyXiang8787 Nov 25, 2025
fa6fdf9
c-api ready
TonyXiang8787 Nov 25, 2025
65888cd
revert python side
TonyXiang8787 Nov 25, 2025
61e915f
adjust python chaining
TonyXiang8787 Nov 25, 2025
fb22a70
python side ready
TonyXiang8787 Nov 25, 2025
79936a6
fix format
TonyXiang8787 Nov 26, 2025
2e0ff73
fix format
TonyXiang8787 Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ template <dataset_type_tag dataset_type_> class Dataset {
}
constexpr bool is_dense(Idx const i) const { return is_dense(buffers_[i]); }
constexpr bool is_dense(Buffer const& buffer) const { return buffer.indptr.empty(); }
constexpr bool is_dense() const {
return std::ranges::all_of(buffers_, [this](Buffer const& buffer) { return is_dense(buffer); });
}
constexpr bool is_sparse(std::string_view component, bool with_attribute_buffers = false) const {
Idx const idx = find_component(component, false);
if (idx == invalid_index) {
Expand Down Expand Up @@ -510,10 +513,43 @@ template <dataset_type_tag dataset_type_> class Dataset {
return result;
}

// get slice dataset from batch
Dataset get_slice_scenario(Idx begin, Idx end) const
requires(!is_indptr_mutable_v<dataset_type>)
{
assert(begin <= end);
assert(0 <= begin);
assert(end <= batch_size());
assert(is_batch());
assert(is_dense());

// empty slice
if (begin == end) {
Dataset result{true, 0, dataset_info_.dataset->name, *meta_data_};
result.add_buffer("node", 0, 0, nullptr, nullptr);
return result;
}

// start with begin
Dataset result = get_individual_scenario(begin);
Idx const batch_size = end - begin;
result.dataset_info_.is_batch = true;
result.dataset_info_.batch_size = batch_size;
for (auto&& [buffer, component_info] : std::views::zip(result.buffers_, result.dataset_info_.component_info)) {
Idx const size = component_info.elements_per_scenario * batch_size;
component_info.total_elements = size;
}
return result;
}

void set_next(Dataset const* next) { next_ = next; }
Dataset const* get_next() const { return next_; }

private:
MetaData const* meta_data_;
DatasetInfo dataset_info_;
std::vector<Buffer> buffers_;
Dataset const* next_{};

std::span<Indptr> get_indptr_span(Indptr* indptr) const {
return std::span{indptr, static_cast<size_t>(batch_size() + 1)};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ PGM_API void PGM_dataset_const_add_attribute_buffer(PGM_Handle* handle, PGM_Cons
*/
PGM_API PGM_DatasetInfo const* PGM_dataset_const_get_info(PGM_Handle* handle, PGM_ConstDataset const* dataset);

/**
* @brief Set next const dataset for chaining for MD batch
*
* @param handle
* @param dataset
* @param next_dataset The next dataset in the chain.
*/
PGM_API void PGM_dataset_const_set_next(PGM_Handle* handle, PGM_ConstDataset* dataset,
PGM_ConstDataset const* next_dataset);

/**
* @brief Get the dataset info of the instance PGM_WritableDataset.
* @param handle
Expand Down
5 changes: 5 additions & 0 deletions power_grid_model_c/power_grid_model_c/src/dataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ void PGM_dataset_const_add_attribute_buffer(PGM_Handle* handle, PGM_ConstDataset
PGM_regular_error);
}

void PGM_dataset_const_set_next(PGM_Handle* /*unused*/, PGM_ConstDataset* dataset,
PGM_ConstDataset const* next_dataset) {
dataset->set_next(next_dataset);
}

PGM_DatasetInfo const* PGM_dataset_const_get_info(PGM_Handle* /*unused*/, PGM_ConstDataset const* dataset) {
return &dataset->get_description();
}
Expand Down
94 changes: 91 additions & 3 deletions power_grid_model_c/power_grid_model_c/src/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#include <power_grid_model/common/common.hpp>
#include <power_grid_model/main_model.hpp>

#include <memory>
#include <numeric>

namespace {
using namespace power_grid_model;
} // namespace
Expand Down Expand Up @@ -55,6 +58,7 @@
PGM_regular_error);
}

// helper functions
namespace {
void check_no_experimental_features_used(MainModel const& model, MainModel::Options const& opt) {
// optionally add experimental feature checks here
Expand Down Expand Up @@ -142,9 +146,11 @@
}
} // namespace

// run calculation
void PGM_calculate(PGM_Handle* handle, PGM_PowerGridModel* model, PGM_Options const* opt,
PGM_MutableDataset const* output_dataset, PGM_ConstDataset const* batch_dataset) {
// calculation implementation
namespace {

void calculate_impl(PGM_Handle* handle, PGM_PowerGridModel* model, PGM_Options const* opt,
PGM_MutableDataset const* output_dataset, PGM_ConstDataset const* batch_dataset) {
PGM_clear_error(handle);
// check dataset integrity
if ((batch_dataset != nullptr) && (!batch_dataset->is_batch() || !output_dataset->is_batch())) {
Expand All @@ -171,14 +177,96 @@
handle->err_msg = e.what();
handle->failed_scenarios = e.failed_scenarios();
handle->batch_errs = e.err_msgs();
} catch (std::exception& e) {

Check warning on line 180 in power_grid_model_c/power_grid_model_c/src/model.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Catch a more specific exception instead of a generic one.

See more on https://sonarcloud.io/project/issues?id=PowerGridModel_power-grid-model&issues=AZq7nlFpDINOUa6eRbcY&open=AZq7nlFpDINOUa6eRbcY&pullRequest=1201
handle->err_code = PGM_regular_error;
handle->err_msg = e.what();
} catch (...) {

Check warning on line 183 in power_grid_model_c/power_grid_model_c/src/model.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

"catch" a specific exception type.

See more on https://sonarcloud.io/project/issues?id=PowerGridModel_power-grid-model&issues=AZq7nlFpDINOUa6eRbcZ&open=AZq7nlFpDINOUa6eRbcZ&pullRequest=1201
handle->err_code = PGM_regular_error;
handle->err_msg = "Unknown error!\n";
}
}

void merge_batch_error_msgs(PGM_Handle* handle, PGM_Handle const& local_handle, Idx scenario_offset, Idx stride_size) {
if (local_handle.err_code == PGM_no_error) {
return;
}
handle->err_code = PGM_batch_error;
if (local_handle.err_code == PGM_batch_error) {
for (auto&& [idx, err_msg] : std::views::zip(local_handle.failed_scenarios, local_handle.batch_errs)) {
handle->failed_scenarios.push_back(idx + scenario_offset);
handle->batch_errs.push_back(err_msg);
}
} else {
for (Idx i = 0; i < stride_size; ++i) {
handle->failed_scenarios.push_back(scenario_offset + i);
handle->batch_errs.push_back(local_handle.err_msg);
}
}
}

Idx get_batch_dimension(PGM_ConstDataset const* batch_dataset) {
Idx dimension = 0;
while (batch_dataset != nullptr) {
++dimension;
batch_dataset = batch_dataset->get_next();
}
return dimension;
}

} // namespace

// run calculation
void PGM_calculate(PGM_Handle* handle, PGM_PowerGridModel* model, PGM_Options const* opt,
PGM_MutableDataset const* output_dataset, PGM_ConstDataset const* batch_dataset) {
Idx const batch_dimension = get_batch_dimension(batch_dataset);

// for dimension < 2 (one-time or 1D batch), call implementation directly
if (batch_dimension < 2) {

Check warning on line 224 in power_grid_model_c/power_grid_model_c/src/model.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the init-statement to declare "batch_dimension" inside the if statement.

See more on https://sonarcloud.io/project/issues?id=PowerGridModel_power-grid-model&issues=AZq7nlFpDINOUa6eRbca&open=AZq7nlFpDINOUa6eRbca&pullRequest=1201
calculate_impl(handle, model, opt, output_dataset, batch_dataset);
return;
}

// get stride size of the rest of dimensions
Idx const first_batch_size = batch_dataset->batch_size();
Idx const stride_size = [batch_dataset]() {
Idx size = 1;
PGM_ConstDataset const* current = batch_dataset->get_next();
while (current != nullptr) {
size *= current->batch_size();
current = current->get_next();
}
return size;
}();

// loop over the first dimension batche
for (Idx i = 0; i < first_batch_size; ++i) {
// a new handle
PGM_Handle local_handle{};
// create sliced datasets for the rest of dimensions
PGM_ConstDataset const single_update_dataset = batch_dataset->get_individual_scenario(i);
PGM_MutableDataset const sliced_output_dataset =
output_dataset->get_slice_scenario(i * stride_size, (i + 1) * stride_size);

// create a model copy
std::unique_ptr<PGM_PowerGridModel> const local_model{PGM_copy_model(&local_handle, model)};

Check warning on line 251 in power_grid_model_c/power_grid_model_c/src/model.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use "std::make_unique" to construct "std::unique_ptr".

See more on https://sonarcloud.io/project/issues?id=PowerGridModel_power-grid-model&issues=AZq7nlFpDINOUa6eRbcb&open=AZq7nlFpDINOUa6eRbcb&pullRequest=1201
if (local_handle.err_code != PGM_no_error) {
merge_batch_error_msgs(handle, local_handle, i * stride_size, stride_size);
continue;
}

// apply the update
PGM_update_model(&local_handle, local_model.get(), &single_update_dataset);
if (local_handle.err_code != PGM_no_error) {
merge_batch_error_msgs(handle, local_handle, i * stride_size, stride_size);
continue;
}

// recursive call
PGM_calculate(&local_handle, local_model.get(), opt, &sliced_output_dataset, batch_dataset->get_next());
// merge errors
merge_batch_error_msgs(handle, local_handle, i * stride_size, stride_size);
}
}

// destroy model
void PGM_destroy_model(PGM_PowerGridModel* model) { delete model; }
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ class DatasetConst {
data.get());
}

void set_next(DatasetConst const& next_dataset) {
handle_.call_with(PGM_dataset_const_set_next, get(), next_dataset.get());
}

DatasetInfo const& get_info() const { return info_; }

private:
Expand Down
4 changes: 4 additions & 0 deletions src/power_grid_model/_core/power_grid_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@ def destroy_dataset_const(self, dataset: ConstDatasetPtr) -> None: # type: igno
def dataset_const_get_info(self, dataset: ConstDatasetPtr) -> DatasetInfoPtr: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
def dataset_const_set_next(self, dataset: ConstDatasetPtr, next_dataset: ConstDatasetPtr) -> None: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
def dataset_writable_get_info(self, dataset: WritableDatasetPtr) -> DatasetInfoPtr: # type: ignore[empty-body]
pass # pragma: no cover
Expand Down
10 changes: 10 additions & 0 deletions src/power_grid_model/_core/power_grid_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,16 @@ def get_info(self) -> CDatasetInfo:
"""
return CDatasetInfo(pgc.dataset_const_get_info(self._const_dataset))

def set_next(self, next_dataset: "CConstDataset") -> None:
"""
Set the next dataset in the linked list.

Args:
next_dataset: The next dataset to set.
"""
pgc.dataset_const_set_next(self._const_dataset, next_dataset._const_dataset)
assert_no_error()

def __del__(self):
pgc.destroy_dataset_const(self._const_dataset)

Expand Down
Loading
Loading