diff --git a/.clang-tidy b/.clang-tidy index 54771a03c..ceb663e50 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,6 +55,7 @@ readability-*, -readability-function-cognitive-complexity, -readability-identifier-length, -readability-magic-numbers, +-bugprone-unchecked-optional-access, ' WarningsAsErrors: '*' diff --git a/.github/workflows/citations.yml b/.github/workflows/citations.yml index 05aee1ffb..99e41cd5a 100644 --- a/.github/workflows/citations.yml +++ b/.github/workflows/citations.yml @@ -35,4 +35,4 @@ jobs: run: | sudo apt-get update && sudo apt-get install -y r-base - name: Validate CITATION.cff - uses: dieghernan/cff-validator@v3 + uses: dieghernan/cff-validator@v4 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f6289e0a1..6bacedce2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -188,7 +188,7 @@ jobs: os: ubuntu-24.04 cibw_build: "*_x86_64" - platform: linux-aarch64 - os: ubuntu-24.04 + os: ubuntu-24.04-arm cibw_build: "*_aarch64" - platform: macos os: macos-14 @@ -208,10 +208,6 @@ jobs: name: version path: . - - name: Set up QEMU - if: matrix.os == 'ubuntu-24.04' - uses: docker/setup-qemu-action@v3 - - name: Set up XCode if: matrix.os == 'macos-14' uses: maxim-lobanov/setup-xcode@v1 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 2b233696d..064ce179a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -12,6 +12,8 @@ build: os: "ubuntu-22.04" tools: python: "3.11" + apt_packages: + - graphviz jobs: post_install: # Build package with doc requirements from pyproject.optional-dependencies @@ -21,6 +23,11 @@ build: - find power_grid_model_c/power_grid_model_c/include -name *.h -exec sed -i -r "s/PGM_API //g" {} \; # build doxygen for C header - cd docs/doxygen && doxygen && cd ../.. + # build class and package diagrams + - pyreverse --no-standalone -o dot src/power_grid_model + - ccomps -x classes.dot | dot -Grankdir=LR -Nfontsize=13 -Efontsize=13 | gvpack -m100 -array_l1 | neato -n2 -Tsvg -o docs/_static/classes.svg + - dot packages.dot -Grankdir=TD -Nfontsize=13 -Efontsize=13 -Tsvg -o docs/_static/packages.svg + - rm packages.dot classes.dot # download support - wget -P docs/release_and_support https://github.com/PowerGridModel/.github/raw/main/RELEASE.md - wget -P docs/release_and_support https://github.com/PowerGridModel/.github/raw/main/SUPPORT.md diff --git a/CMakeLists.txt b/CMakeLists.txt index be6024241..0f02de07d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,13 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) include(GNUInstallDirs) -find_package(Eigen3 CONFIG REQUIRED) +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30.0") +# libboost-headers packaged by conda does not come with BoostConfig.cmake +cmake_policy(SET CMP0167 OLD) +endif() + find_package(Boost REQUIRED) +find_package(Eigen3 CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) find_package(msgpack-cxx REQUIRED) diff --git a/CMakePresets.json b/CMakePresets.json index f108ed991..89896f5ef 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -254,7 +254,10 @@ }, { "name": "ci-clang-release", - "inherits": "clang-release" + "inherits": "clang-release", + "cacheVariables": { + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "TRUE" + } }, { "name": "ci-gcc-debug", @@ -270,7 +273,13 @@ "name": "ci-gcc-release", "inherits": [ "gcc-release" - ] + ], + "cacheVariables": { + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "TRUE" + }, + "environment": { + "ASAN_OPTIONS": "detect_odr_violation=0" + } }, { "name": "ci-sonar", diff --git a/README.md b/README.md index d5242a5df..cf9ad84d6 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Currently, it supports the following calculations: See the [power-grid-model documentation](https://power-grid-model.readthedocs.io/en/stable/) for more information. For various conversions to the power-grid-model, refer to the [power-grid-model-io](https://github.com/PowerGridModel/power-grid-model-io) repository. +For an extended python interface to the the power-grid-model, refer to the [power-grid-model-ds](https://github.com/PowerGridModel/power-grid-model-ds) repository. ```{note} Want to be updated on the latest news and releases? Subscribe to the Power Grid Model mailing list by sending an (empty) email to: powergridmodel+subscribe@lists.lfenergy.org diff --git a/code_generation/data/attribute_classes/input.json b/code_generation/data/attribute_classes/input.json index dea1c0fdd..7cf8b5c97 100644 --- a/code_generation/data/attribute_classes/input.json +++ b/code_generation/data/attribute_classes/input.json @@ -494,6 +494,45 @@ "description": "line drop compensation reactance" } ] + }, + { + "name": "GenericCurrentSensorInput", + "base": "SensorInput", + "attributes": [ + { + "data_type": "MeasuredTerminalType", + "names": "measured_terminal_type", + "description": "type of measured terminal" + }, + { + "data_type": "AngleMeasurementType", + "names": "angle_measurement_type", + "description": "type of angle measurement" + }, + { + "data_type": "double", + "names": [ + "i_sigma", + "i_angle_sigma" + ], + "description": "sigma of error margin of current (angle) measurement" + } + ] + }, + { + "name": "CurrentSensorInput", + "base": "GenericCurrentSensorInput", + "is_template": true, + "attributes": [ + { + "data_type": "RealValue", + "names": [ + "i_measured", + "i_angle_measured" + ], + "description": "measured current and current angle" + } + ] } ] } \ No newline at end of file diff --git a/code_generation/data/attribute_classes/output.json b/code_generation/data/attribute_classes/output.json index 3fd789e6d..b8c310850 100644 --- a/code_generation/data/attribute_classes/output.json +++ b/code_generation/data/attribute_classes/output.json @@ -293,6 +293,21 @@ "base": "BaseOutput", "is_template": false, "attributes": [] + }, + { + "name": "CurrentSensorOutput", + "base": "BaseOutput", + "is_template": true, + "attributes": [ + { + "data_type": "RealValue", + "names": [ + "i_residual", + "i_angle_residual" + ], + "description": "deviation between the measured value and calculated value" + } + ] } ] } \ No newline at end of file diff --git a/code_generation/data/attribute_classes/update.json b/code_generation/data/attribute_classes/update.json index a57205b17..db87d7bd1 100644 --- a/code_generation/data/attribute_classes/update.json +++ b/code_generation/data/attribute_classes/update.json @@ -243,6 +243,29 @@ "description": "line drop compensation reactance" } ] + }, + { + "name": "CurrentSensorUpdate", + "base": "BaseUpdate", + "is_template": true, + "attributes": [ + { + "data_type": "double", + "names": [ + "i_sigma", + "i_angle_sigma" + ], + "description": "sigma of error margin of current (angle) measurement" + }, + { + "data_type": "RealValue", + "names": [ + "i_measured", + "i_angle_measured" + ], + "description": "measured current and current angle" + } + ] } ] } \ No newline at end of file diff --git a/docs/advanced_documentation/python-wrapper-design.md b/docs/advanced_documentation/python-wrapper-design.md new file mode 100644 index 000000000..06f8569d5 --- /dev/null +++ b/docs/advanced_documentation/python-wrapper-design.md @@ -0,0 +1,37 @@ + + +# Design of the Python Wrapper Package + +The structure of the `power_grid_model` Python package is shown here below by means of the corresponding class and package diagrams. + +## Class Graph Diagram + +This is the class diagram of the `power_grid_model` package. + +```{note} +Only classes that have connections to other classes are shown in this diagram. +``` + +```{raw} html +
+ Classe diagram +
. +``` + +## Package Graph Diagram + +This is the package diagram of the `power_grid_model` package. + +```{note} +Only modules that import (or are impored by) other modules are shown in this diagram. +``` + +```{raw} html +
+ Package diagram +
. +``` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index f03a784d6..5daa481e0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,6 +22,7 @@ Currently, it supports both symmetric and asymmetric calculations for the follow * Short Circuit For conversions from various data format to the power-grid-model, refer to the [power-grid-model-io](https://github.com/PowerGridModel/power-grid-model-io) repository. +For an extended python interface to the the power-grid-model, refer to the [power-grid-model-ds](https://github.com/PowerGridModel/power-grid-model-ds) repository. ```{note} Do you wish to be updated on the latest news and releases? Subscribe to the Power Grid Model mailing list by sending an (empty) email to: powergridmodel+subscribe@lists.lfenergy.org @@ -100,6 +101,7 @@ advanced_documentation/native-data-interface advanced_documentation/build-guide advanced_documentation/c-api advanced_documentation/core-design +advanced_documentation/python-wrapper-design ``` ```{toctree} :caption: "Contribution" diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp index ec9eaed24..661579d1c 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp @@ -444,6 +444,52 @@ struct TransformerTapRegulatorInput { operator RegulatorInput const&() const { return reinterpret_cast(*this); } }; +struct GenericCurrentSensorInput { + ID id{na_IntID}; // ID of the object + ID measured_object{na_IntID}; // ID of the measured object + MeasuredTerminalType measured_terminal_type{static_cast(na_IntS)}; // type of measured terminal + AngleMeasurementType angle_measurement_type{static_cast(na_IntS)}; // type of angle measurement + double i_sigma{nan}; // sigma of error margin of current (angle) measurement + double i_angle_sigma{nan}; // sigma of error margin of current (angle) measurement + + // implicit conversions to BaseInput + operator BaseInput&() { return reinterpret_cast(*this); } + operator BaseInput const&() const { return reinterpret_cast(*this); } + + // implicit conversions to SensorInput + operator SensorInput&() { return reinterpret_cast(*this); } + operator SensorInput const&() const { return reinterpret_cast(*this); } +}; + +template +struct CurrentSensorInput { + using sym = sym_type; + + ID id{na_IntID}; // ID of the object + ID measured_object{na_IntID}; // ID of the measured object + MeasuredTerminalType measured_terminal_type{static_cast(na_IntS)}; // type of measured terminal + AngleMeasurementType angle_measurement_type{static_cast(na_IntS)}; // type of angle measurement + double i_sigma{nan}; // sigma of error margin of current (angle) measurement + double i_angle_sigma{nan}; // sigma of error margin of current (angle) measurement + RealValue i_measured{nan}; // measured current and current angle + RealValue i_angle_measured{nan}; // measured current and current angle + + // implicit conversions to BaseInput + operator BaseInput&() { return reinterpret_cast(*this); } + operator BaseInput const&() const { return reinterpret_cast(*this); } + + // implicit conversions to SensorInput + operator SensorInput&() { return reinterpret_cast(*this); } + operator SensorInput const&() const { return reinterpret_cast(*this); } + + // implicit conversions to GenericCurrentSensorInput + operator GenericCurrentSensorInput&() { return reinterpret_cast(*this); } + operator GenericCurrentSensorInput const&() const { return reinterpret_cast(*this); } +}; + +using SymCurrentSensorInput = CurrentSensorInput; +using AsymCurrentSensorInput = CurrentSensorInput; + } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp index 7cca2754f..27deffff7 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp @@ -396,6 +396,38 @@ struct get_attributes_list { }; }; +template<> +struct get_attributes_list { + static constexpr std::array value{ + // all attributes including base class + + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::id>(offsetof(GenericCurrentSensorInput, id), "id"), + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::measured_object>(offsetof(GenericCurrentSensorInput, measured_object), "measured_object"), + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::measured_terminal_type>(offsetof(GenericCurrentSensorInput, measured_terminal_type), "measured_terminal_type"), + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::angle_measurement_type>(offsetof(GenericCurrentSensorInput, angle_measurement_type), "angle_measurement_type"), + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::i_sigma>(offsetof(GenericCurrentSensorInput, i_sigma), "i_sigma"), + meta_data_gen::get_meta_attribute<&GenericCurrentSensorInput::i_angle_sigma>(offsetof(GenericCurrentSensorInput, i_angle_sigma), "i_angle_sigma"), + }; +}; + +template +struct get_attributes_list> { + using sym = sym_type; + + static constexpr std::array value{ + // all attributes including base class + + meta_data_gen::get_meta_attribute<&CurrentSensorInput::id>(offsetof(CurrentSensorInput, id), "id"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::measured_object>(offsetof(CurrentSensorInput, measured_object), "measured_object"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::measured_terminal_type>(offsetof(CurrentSensorInput, measured_terminal_type), "measured_terminal_type"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::angle_measurement_type>(offsetof(CurrentSensorInput, angle_measurement_type), "angle_measurement_type"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::i_sigma>(offsetof(CurrentSensorInput, i_sigma), "i_sigma"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::i_angle_sigma>(offsetof(CurrentSensorInput, i_angle_sigma), "i_angle_sigma"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::i_measured>(offsetof(CurrentSensorInput, i_measured), "i_measured"), + meta_data_gen::get_meta_attribute<&CurrentSensorInput::i_angle_measured>(offsetof(CurrentSensorInput, i_angle_measured), "i_angle_measured"), + }; +}; + diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/output.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/output.hpp index 3d4b62e96..186ec3b56 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/output.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/output.hpp @@ -247,6 +247,20 @@ struct get_attributes_list { }; }; +template +struct get_attributes_list> { + using sym = sym_type; + + static constexpr std::array value{ + // all attributes including base class + + meta_data_gen::get_meta_attribute<&CurrentSensorOutput::id>(offsetof(CurrentSensorOutput, id), "id"), + meta_data_gen::get_meta_attribute<&CurrentSensorOutput::energized>(offsetof(CurrentSensorOutput, energized), "energized"), + meta_data_gen::get_meta_attribute<&CurrentSensorOutput::i_residual>(offsetof(CurrentSensorOutput, i_residual), "i_residual"), + meta_data_gen::get_meta_attribute<&CurrentSensorOutput::i_angle_residual>(offsetof(CurrentSensorOutput, i_angle_residual), "i_angle_residual"), + }; +}; + diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/update.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/update.hpp index d4781bfe8..0e73efc8f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/update.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/update.hpp @@ -197,6 +197,21 @@ struct get_attributes_list { }; }; +template +struct get_attributes_list> { + using sym = sym_type; + + static constexpr std::array value{ + // all attributes including base class + + meta_data_gen::get_meta_attribute<&CurrentSensorUpdate::id>(offsetof(CurrentSensorUpdate, id), "id"), + meta_data_gen::get_meta_attribute<&CurrentSensorUpdate::i_sigma>(offsetof(CurrentSensorUpdate, i_sigma), "i_sigma"), + meta_data_gen::get_meta_attribute<&CurrentSensorUpdate::i_angle_sigma>(offsetof(CurrentSensorUpdate, i_angle_sigma), "i_angle_sigma"), + meta_data_gen::get_meta_attribute<&CurrentSensorUpdate::i_measured>(offsetof(CurrentSensorUpdate, i_measured), "i_measured"), + meta_data_gen::get_meta_attribute<&CurrentSensorUpdate::i_angle_measured>(offsetof(CurrentSensorUpdate, i_angle_measured), "i_angle_measured"), + }; +}; + diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/output.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/output.hpp index 54de1fa69..1fae40845 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/output.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/output.hpp @@ -245,6 +245,23 @@ struct RegulatorShortCircuitOutput { operator BaseOutput const&() const { return reinterpret_cast(*this); } }; +template +struct CurrentSensorOutput { + using sym = sym_type; + + ID id{na_IntID}; // ID of the object + IntS energized{na_IntS}; // whether the object is energized + RealValue i_residual{nan}; // deviation between the measured value and calculated value + RealValue i_angle_residual{nan}; // deviation between the measured value and calculated value + + // implicit conversions to BaseOutput + operator BaseOutput&() { return reinterpret_cast(*this); } + operator BaseOutput const&() const { return reinterpret_cast(*this); } +}; + +using SymCurrentSensorOutput = CurrentSensorOutput; +using AsymCurrentSensorOutput = CurrentSensorOutput; + } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp index ee2288a36..ee0052125 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp @@ -517,6 +517,124 @@ static_assert(offsetof(TransformerTapRegulatorInput, id) == offsetof(RegulatorIn static_assert(offsetof(TransformerTapRegulatorInput, regulated_object) == offsetof(RegulatorInput, regulated_object)); static_assert(offsetof(TransformerTapRegulatorInput, status) == offsetof(RegulatorInput, status)); +// static asserts for GenericCurrentSensorInput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of GenericCurrentSensorInput to BaseInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(GenericCurrentSensorInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of GenericCurrentSensorInput to SensorInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(GenericCurrentSensorInput, id) == offsetof(SensorInput, id)); +static_assert(offsetof(GenericCurrentSensorInput, measured_object) == offsetof(SensorInput, measured_object)); + +// static asserts for CurrentSensorInput +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorInput to BaseInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseInput::id)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of CurrentSensorInput to SensorInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(SensorInput::id)>); +static_assert(std::same_as::measured_object), decltype(SensorInput::measured_object)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(SensorInput, id)); +static_assert(offsetof(CurrentSensorInput, measured_object) == offsetof(SensorInput, measured_object)); +// static asserts for conversion of CurrentSensorInput to GenericCurrentSensorInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(GenericCurrentSensorInput::id)>); +static_assert(std::same_as::measured_object), decltype(GenericCurrentSensorInput::measured_object)>); +static_assert(std::same_as::measured_terminal_type), decltype(GenericCurrentSensorInput::measured_terminal_type)>); +static_assert(std::same_as::angle_measurement_type), decltype(GenericCurrentSensorInput::angle_measurement_type)>); +static_assert(std::same_as::i_sigma), decltype(GenericCurrentSensorInput::i_sigma)>); +static_assert(std::same_as::i_angle_sigma), decltype(GenericCurrentSensorInput::i_angle_sigma)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(GenericCurrentSensorInput, id)); +static_assert(offsetof(CurrentSensorInput, measured_object) == offsetof(GenericCurrentSensorInput, measured_object)); +static_assert(offsetof(CurrentSensorInput, measured_terminal_type) == offsetof(GenericCurrentSensorInput, measured_terminal_type)); +static_assert(offsetof(CurrentSensorInput, angle_measurement_type) == offsetof(GenericCurrentSensorInput, angle_measurement_type)); +static_assert(offsetof(CurrentSensorInput, i_sigma) == offsetof(GenericCurrentSensorInput, i_sigma)); +static_assert(offsetof(CurrentSensorInput, i_angle_sigma) == offsetof(GenericCurrentSensorInput, i_angle_sigma)); +// static asserts for CurrentSensorInput +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorInput to BaseInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseInput::id)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of CurrentSensorInput to SensorInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(SensorInput::id)>); +static_assert(std::same_as::measured_object), decltype(SensorInput::measured_object)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(SensorInput, id)); +static_assert(offsetof(CurrentSensorInput, measured_object) == offsetof(SensorInput, measured_object)); +// static asserts for conversion of CurrentSensorInput to GenericCurrentSensorInput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(GenericCurrentSensorInput::id)>); +static_assert(std::same_as::measured_object), decltype(GenericCurrentSensorInput::measured_object)>); +static_assert(std::same_as::measured_terminal_type), decltype(GenericCurrentSensorInput::measured_terminal_type)>); +static_assert(std::same_as::angle_measurement_type), decltype(GenericCurrentSensorInput::angle_measurement_type)>); +static_assert(std::same_as::i_sigma), decltype(GenericCurrentSensorInput::i_sigma)>); +static_assert(std::same_as::i_angle_sigma), decltype(GenericCurrentSensorInput::i_angle_sigma)>); +static_assert(offsetof(CurrentSensorInput, id) == offsetof(GenericCurrentSensorInput, id)); +static_assert(offsetof(CurrentSensorInput, measured_object) == offsetof(GenericCurrentSensorInput, measured_object)); +static_assert(offsetof(CurrentSensorInput, measured_terminal_type) == offsetof(GenericCurrentSensorInput, measured_terminal_type)); +static_assert(offsetof(CurrentSensorInput, angle_measurement_type) == offsetof(GenericCurrentSensorInput, angle_measurement_type)); +static_assert(offsetof(CurrentSensorInput, i_sigma) == offsetof(GenericCurrentSensorInput, i_sigma)); +static_assert(offsetof(CurrentSensorInput, i_angle_sigma) == offsetof(GenericCurrentSensorInput, i_angle_sigma)); +// static asserts for SymCurrentSensorInput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of SymCurrentSensorInput to BaseInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(SymCurrentSensorInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of SymCurrentSensorInput to SensorInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(SymCurrentSensorInput, id) == offsetof(SensorInput, id)); +static_assert(offsetof(SymCurrentSensorInput, measured_object) == offsetof(SensorInput, measured_object)); +// static asserts for conversion of SymCurrentSensorInput to GenericCurrentSensorInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(SymCurrentSensorInput, id) == offsetof(GenericCurrentSensorInput, id)); +static_assert(offsetof(SymCurrentSensorInput, measured_object) == offsetof(GenericCurrentSensorInput, measured_object)); +static_assert(offsetof(SymCurrentSensorInput, measured_terminal_type) == offsetof(GenericCurrentSensorInput, measured_terminal_type)); +static_assert(offsetof(SymCurrentSensorInput, angle_measurement_type) == offsetof(GenericCurrentSensorInput, angle_measurement_type)); +static_assert(offsetof(SymCurrentSensorInput, i_sigma) == offsetof(GenericCurrentSensorInput, i_sigma)); +static_assert(offsetof(SymCurrentSensorInput, i_angle_sigma) == offsetof(GenericCurrentSensorInput, i_angle_sigma)); +// static asserts for AsymCurrentSensorInput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of AsymCurrentSensorInput to BaseInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(AsymCurrentSensorInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of AsymCurrentSensorInput to SensorInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(AsymCurrentSensorInput, id) == offsetof(SensorInput, id)); +static_assert(offsetof(AsymCurrentSensorInput, measured_object) == offsetof(SensorInput, measured_object)); +// static asserts for conversion of AsymCurrentSensorInput to GenericCurrentSensorInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(AsymCurrentSensorInput, id) == offsetof(GenericCurrentSensorInput, id)); +static_assert(offsetof(AsymCurrentSensorInput, measured_object) == offsetof(GenericCurrentSensorInput, measured_object)); +static_assert(offsetof(AsymCurrentSensorInput, measured_terminal_type) == offsetof(GenericCurrentSensorInput, measured_terminal_type)); +static_assert(offsetof(AsymCurrentSensorInput, angle_measurement_type) == offsetof(GenericCurrentSensorInput, angle_measurement_type)); +static_assert(offsetof(AsymCurrentSensorInput, i_sigma) == offsetof(GenericCurrentSensorInput, i_sigma)); +static_assert(offsetof(AsymCurrentSensorInput, i_angle_sigma) == offsetof(GenericCurrentSensorInput, i_angle_sigma)); + } // namespace power_grid_model::test diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/output.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/output.hpp index 54a5d5f55..9de483618 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/output.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/output.hpp @@ -295,6 +295,39 @@ static_assert(std::same_as +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorOutput to BaseOutput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseOutput::id)>); +static_assert(std::same_as::energized), decltype(BaseOutput::energized)>); +static_assert(offsetof(CurrentSensorOutput, id) == offsetof(BaseOutput, id)); +static_assert(offsetof(CurrentSensorOutput, energized) == offsetof(BaseOutput, energized)); +// static asserts for CurrentSensorOutput +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorOutput to BaseOutput +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseOutput::id)>); +static_assert(std::same_as::energized), decltype(BaseOutput::energized)>); +static_assert(offsetof(CurrentSensorOutput, id) == offsetof(BaseOutput, id)); +static_assert(offsetof(CurrentSensorOutput, energized) == offsetof(BaseOutput, energized)); +// static asserts for SymCurrentSensorOutput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of SymCurrentSensorOutput to BaseOutput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(SymCurrentSensorOutput, id) == offsetof(BaseOutput, id)); +static_assert(offsetof(SymCurrentSensorOutput, energized) == offsetof(BaseOutput, energized)); +// static asserts for AsymCurrentSensorOutput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of AsymCurrentSensorOutput to BaseOutput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(AsymCurrentSensorOutput, id) == offsetof(BaseOutput, id)); +static_assert(offsetof(AsymCurrentSensorOutput, energized) == offsetof(BaseOutput, energized)); + } // namespace power_grid_model::test diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/update.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/update.hpp index dc244f783..7579606b2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/update.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/update.hpp @@ -221,6 +221,31 @@ static_assert(std::same_as +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorUpdate to BaseUpdate +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseUpdate::id)>); +static_assert(offsetof(CurrentSensorUpdate, id) == offsetof(BaseUpdate, id)); +// static asserts for CurrentSensorUpdate +static_assert(std::is_standard_layout_v>); +// static asserts for conversion of CurrentSensorUpdate to BaseUpdate +static_assert(std::alignment_of_v> >= std::alignment_of_v); +static_assert(std::same_as::id), decltype(BaseUpdate::id)>); +static_assert(offsetof(CurrentSensorUpdate, id) == offsetof(BaseUpdate, id)); +// static asserts for SymCurrentSensorUpdate +static_assert(std::is_standard_layout_v); +// static asserts for conversion of SymCurrentSensorUpdate to BaseUpdate +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(SymCurrentSensorUpdate, id) == offsetof(BaseUpdate, id)); +// static asserts for AsymCurrentSensorUpdate +static_assert(std::is_standard_layout_v); +// static asserts for conversion of AsymCurrentSensorUpdate to BaseUpdate +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(AsymCurrentSensorUpdate, id) == offsetof(BaseUpdate, id)); + } // namespace power_grid_model::test diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/update.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/update.hpp index d5dba7a67..a30b69fba 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/update.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/update.hpp @@ -209,6 +209,24 @@ struct TransformerTapRegulatorUpdate { operator RegulatorUpdate const&() const { return reinterpret_cast(*this); } }; +template +struct CurrentSensorUpdate { + using sym = sym_type; + + ID id{na_IntID}; // ID of the object + double i_sigma{nan}; // sigma of error margin of current (angle) measurement + double i_angle_sigma{nan}; // sigma of error margin of current (angle) measurement + RealValue i_measured{nan}; // measured current and current angle + RealValue i_angle_measured{nan}; // measured current and current angle + + // implicit conversions to BaseUpdate + operator BaseUpdate&() { return reinterpret_cast(*this); } + operator BaseUpdate const&() const { return reinterpret_cast(*this); } +}; + +using SymCurrentSensorUpdate = CurrentSensorUpdate; +using AsymCurrentSensorUpdate = CurrentSensorUpdate; + } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/calculation_parameters.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/calculation_parameters.hpp index 53cf13953..8e70e3f11 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/calculation_parameters.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/calculation_parameters.hpp @@ -108,6 +108,20 @@ template struct PowerSensorCalcParam { RealValue q_variance{}; // variance (sigma^2) of the error range of the reactive power, in p.u. }; +// current sensor calculation parameters for state estimation +// The value is the complex current +// * for branches, the direction is node -> branch +template struct CurrentSensorCalcParam { + using sym = sym_type; + + static constexpr bool symmetric{is_symmetric_v}; + + AngleMeasurementType angle_measurement_type{}; + ComplexValue value{}; + double i_real_variance{}; // variance (sigma^2) of the error range of real part of the current, in p.u. + double i_imag_variance{}; // variance (sigma^2) of the error range of imaginary part of the current, in p.u. +}; + template concept sensor_calc_param_type = std::derived_from> || diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp index 43c6d78ce..740d40531 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp @@ -91,4 +91,10 @@ using IntSVector = std::vector; template concept is_in_list_c = (std::same_as, Ts> || ...); +// functor to include all +struct IncludeAll { + template constexpr bool operator()(T&&... /*ignored*/) const { return true; } +}; +constexpr IncludeAll include_all{}; + } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp index 5d5c504ef..01e7cbc3c 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp @@ -128,4 +128,9 @@ enum class SearchMethod : IntS { // Which type of tap search method for finite e binary_search = 1, // use binary search: half a tap range at a time }; +enum class AngleMeasurementType : IntS { // The type of the angle measurement for current sensors + local = 0, // local = 0, the angle is relative to the local voltage angle + global = 1, // global = 1, the angle is relative to the global voltage angle +}; + } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp index 7846173cf..5b3990621 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp @@ -108,7 +108,7 @@ class SparseMatrixError : public PowerGridError { std::string("If you get this error from state estimation, ") + "it might mean the system is not fully observable, i.e. not enough measurements.\n" + "It might also mean that you are running into a corner case where PGM cannot resolve yet." + - "See https://github.com/PowerGridModel/power-grid-model/issues/853."); + "See https://github.com/PowerGridModel/power-grid-model/issues/864."); } }; @@ -135,7 +135,7 @@ class IterationDiverge : public PowerGridError { class MaxIterationReached : public IterationDiverge { public: MaxIterationReached(std::string const& msg = "") { - append_msg("Maximum iterations reached, no solution. " + msg + "\n"); + append_msg("Maximum number of iterations reached" + msg + "\n"); } }; @@ -163,6 +163,14 @@ class InvalidMeasuredObject : public PowerGridError { } }; +class InvalidMeasuredTerminalType : public PowerGridError { + public: + InvalidMeasuredTerminalType(MeasuredTerminalType const terminal_type, std::string const& sensor) { + append_msg(sensor + " measurement is not supported for object of type " + + detail::to_string(static_cast(terminal_type))); + } +}; + class InvalidRegulatedObject : public PowerGridError { public: InvalidRegulatedObject(std::string const& object, std::string const& regulator) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp index 6523933ea..afd72324e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp @@ -152,9 +152,18 @@ inline ComplexValue piecewise_complex_value(ComplexValue inline auto cabs(Eigen::ArrayBase const& m) { +template +inline auto cabs(Eigen::ArrayBase const& m) + requires(std::same_as) +{ return sqrt(abs2(m)); } +template +inline auto cabs(Eigen::ArrayBase const& m) + requires(std::same_as) +{ + return m.abs(); +} // phase_shift(x) = e^{i arg(x)} = x / |x| inline DoubleComplex phase_shift(DoubleComplex const x) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/current_sensor.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/current_sensor.hpp new file mode 100644 index 000000000..cbfd1ac8c --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/current_sensor.hpp @@ -0,0 +1,162 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "sensor.hpp" + +#include "../calculation_parameters.hpp" +#include "../common/common.hpp" +#include "../common/enum.hpp" +#include "../common/exception.hpp" + +namespace power_grid_model { + +class GenericCurrentSensor : public Sensor { + public: + static constexpr char const* name = "generic_current_sensor"; + + explicit GenericCurrentSensor(GenericCurrentSensorInput const& generic_current_sensor_input) + : Sensor{generic_current_sensor_input}, + terminal_type_{generic_current_sensor_input.measured_terminal_type}, + angle_measurement_type_{generic_current_sensor_input.angle_measurement_type} {} + + MeasuredTerminalType get_terminal_type() const { return terminal_type_; } + AngleMeasurementType get_angle_measurement_type() const { return angle_measurement_type_; } + + template CurrentSensorOutput get_output(ComplexValue const& i) const { + if constexpr (is_symmetric_v) { + return get_sym_output(i); + } else { + return get_asym_output(i); + } + } + + template CurrentSensorOutput get_null_output() const { + return {.id = id(), .energized = false, .i_residual = {}, .i_angle_residual = {}}; + } + + SensorShortCircuitOutput get_null_sc_output() const { return {.id = id(), .energized = 0}; } + + // getter for calculation param + template CurrentSensorCalcParam calc_param() const { + if constexpr (is_symmetric_v) { + return sym_calc_param(); + } else { + return asym_calc_param(); + } + } + + private: + MeasuredTerminalType terminal_type_; + AngleMeasurementType angle_measurement_type_; + + // virtual function getter for sym and asym param + // override them in real sensors function + virtual CurrentSensorCalcParam sym_calc_param() const = 0; + virtual CurrentSensorCalcParam asym_calc_param() const = 0; + + virtual CurrentSensorOutput get_sym_output(ComplexValue const& i) const = 0; + virtual CurrentSensorOutput get_asym_output(ComplexValue const& i) const = 0; +}; + +template class CurrentSensor : public GenericCurrentSensor { + public: + using current_sensor_symmetry = current_sensor_symmetry_; + + static constexpr char const* name = + is_symmetric_v ? "sym_current_sensor" : "asym_current_sensor"; + using InputType = CurrentSensorInput; + using UpdateType = CurrentSensorUpdate; + template using OutputType = CurrentSensorOutput; + + explicit CurrentSensor(CurrentSensorInput const& current_sensor_input, double u_rated) + : GenericCurrentSensor{current_sensor_input}, + i_angle_measured_{current_sensor_input.i_angle_measured}, + i_angle_sigma_{current_sensor_input.i_angle_sigma}, + base_current_{base_power_3p * inv_sqrt3 / u_rated}, + base_current_inv_{1.0 / base_current_} { + set_current(current_sensor_input); + + switch (current_sensor_input.measured_terminal_type) { + using enum MeasuredTerminalType; + case branch_from: + case branch_to: + case branch3_1: + case branch3_2: + case branch3_3: + break; + default: + throw InvalidMeasuredTerminalType{current_sensor_input.measured_terminal_type, "Current sensor"}; + } + }; + + UpdateChange update(CurrentSensorUpdate const& update_data) { + if (!is_nan(update_data.i_sigma)) { + i_sigma_ = update_data.i_sigma * base_current_inv_; + } + if (!is_nan(update_data.i_angle_sigma)) { + i_angle_sigma_ = update_data.i_angle_sigma; + } + update_real_value(update_data.i_measured, i_measured_, base_current_inv_); + update_real_value(update_data.i_angle_measured, i_angle_measured_, 1.0); + return {false, false}; + } + + CurrentSensorUpdate + inverse(CurrentSensorUpdate update_data) const { + assert(update_data.id == this->id() || is_nan(update_data.id)); + + set_if_not_nan(update_data.i_sigma, i_sigma_ * base_current_); + set_if_not_nan(update_data.i_angle_sigma, i_angle_sigma_); + set_if_not_nan(update_data.i_measured, i_measured_ * base_current_); + set_if_not_nan(update_data.i_angle_measured, i_angle_measured_); + + return update_data; + } + + private: + RealValue i_measured_{}; + RealValue i_angle_measured_{}; + double i_sigma_{}; + double i_angle_sigma_{}; + double base_current_{}; + double base_current_inv_{}; + + void set_current(CurrentSensorInput const& input) { + i_sigma_ = input.i_sigma * base_current_inv_; + i_measured_ = input.i_measured * base_current_inv_; + } + + // TODO when filling the functions below take in mind that i_angle_sigma is optional + + CurrentSensorCalcParam sym_calc_param() const final { + CurrentSensorCalcParam calc_param{}; + // TODO + return calc_param; + } + CurrentSensorCalcParam asym_calc_param() const final { + CurrentSensorCalcParam calc_param{}; + // TODO + return calc_param; + } + CurrentSensorOutput get_sym_output(ComplexValue const& i) const final { + return get_generic_output(i); + } + CurrentSensorOutput get_asym_output(ComplexValue const& i) const final { + return get_generic_output(i); + } + template + CurrentSensorOutput get_generic_output(ComplexValue const& i) const { + CurrentSensorOutput output{}; + // TODO + (void)i; // Suppress unused variable warning + return output; + } +}; + +using SymCurrentSensor = CurrentSensor; +using AsymCurrentSensor = CurrentSensor; + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index a512fc834..9113e1844 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -1014,8 +1014,6 @@ class MainModelImpl, ComponentLis return math_param_increment; } - static constexpr auto include_all = [](Idx) { return true; }; - /** This is a heavily templated member function because it operates on many different variables of many *different types, but the essence is ever the same: filling one member (vector) of the calculation calc_input *struct (soa) with the right calculation symmetric or asymmetric calculation parameters, in the same order as @@ -1068,7 +1066,7 @@ class MainModelImpl, ComponentLis */ template (CalcStructOut::*comp_vect), class ComponentIn, - std::invocable PredicateIn = decltype(include_all)> + std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, std::vector& calc_input, PredicateIn include = include_all) { @@ -1087,7 +1085,7 @@ class MainModelImpl, ComponentLis template (CalcStructOut::*comp_vect), class ComponentIn, - std::invocable PredicateIn = decltype(include_all)> + std::invocable PredicateIn = IncludeAll> requires std::convertible_to, bool> static void prepare_input(MainModelState const& state, std::vector const& components, std::vector& calc_input, diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/iterative_linear_se_solver.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/iterative_linear_se_solver.hpp index 0eca1af4f..2b440b9b5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/iterative_linear_se_solver.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/iterative_linear_se_solver.hpp @@ -95,11 +95,14 @@ template class IterativeLinearSESolver { // preprocess measured value sub_timer = Timer(calculation_info, 2221, "Pre-process measured value"); MeasuredValues const measured_values{y_bus.shared_topology(), input}; - necessary_observability_check(measured_values, y_bus.math_topology(), y_bus.y_bus_structure()); + auto const observability_result = + necessary_observability_check(measured_values, y_bus.math_topology(), y_bus.y_bus_structure()); - // prepare matrix, including pre-factorization + // prepare matrix sub_timer = Timer(calculation_info, 2222, "Prepare matrix, including pre-factorization"); prepare_matrix(y_bus, measured_values); + // prefactorize + sparse_solver_.prefactorize(data_gain_, perm_, observability_result.use_perturbation()); // initialize voltage with initial angle sub_timer = Timer(calculation_info, 2223, "Initialize voltages"); @@ -252,8 +255,6 @@ template class IterativeLinearSESolver { Idx const data_idx_tranpose = y_bus.lu_transpose_entry()[data_idx_lu]; data_gain_[data_idx_lu].qh() = hermitian_transpose(data_gain_[data_idx_tranpose].q()); } - // prefactorize - sparse_solver_.prefactorize(data_gain_, perm_); } void prepare_rhs(YBus const& y_bus, MeasuredValues const& measured_value, diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/measured_values.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/measured_values.hpp index 2b90c4999..16e8d6ec3 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/measured_values.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/measured_values.hpp @@ -498,9 +498,13 @@ template class MeasuredValues { } // process one object - static constexpr auto default_status_checker = [](auto x) -> bool { return x; }; + struct DefaultStatusChecker { + template bool operator()(T x) const { return x; } + }; + + static constexpr DefaultStatusChecker default_status_checker{}; - template + template static Idx process_one_object(Idx const object, grouped_idx_vector_type auto const& sensors_per_object, std::vector const& object_status, std::vector> const& input_data, diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/newton_raphson_se_solver.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/newton_raphson_se_solver.hpp index 7e3e451f6..a04065c81 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/newton_raphson_se_solver.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/newton_raphson_se_solver.hpp @@ -159,7 +159,8 @@ template class NewtonRaphsonSESolver { // preprocess measured value sub_timer = Timer(calculation_info, 2221, "Pre-process measured value"); MeasuredValues const measured_values{y_bus.shared_topology(), input}; - necessary_observability_check(measured_values, y_bus.math_topology(), y_bus.y_bus_structure()); + auto const observability_result = + necessary_observability_check(measured_values, y_bus.math_topology(), y_bus.y_bus_structure()); // initialize voltage with initial angle sub_timer = Timer(calculation_info, 2223, "Initialize voltages"); @@ -175,7 +176,8 @@ template class NewtonRaphsonSESolver { prepare_matrix_and_rhs(y_bus, measured_values, output.u); // solve with prefactorization sub_timer = Timer(calculation_info, 2225, "Solve sparse linear equation"); - sparse_solver_.prefactorize_and_solve(data_gain_, perm_, delta_x_rhs_, delta_x_rhs_); + sparse_solver_.prefactorize_and_solve(data_gain_, perm_, delta_x_rhs_, delta_x_rhs_, + observability_result.use_perturbation()); sub_timer = Timer(calculation_info, 2226, "Iterate unknown"); max_dev = iterate_unknown(output.u, measured_values); }; @@ -519,7 +521,8 @@ template class NewtonRaphsonSESolver { /// eta(row) += w_k . (z_k - f_k(x)) /// /// In case there is no angle measurement, the slack bus or arbitray bus measurement is considered to have a virtual - /// angle measurement of zero. w_theta = 1.0 by default for all measurements + /// angle measurement of zero. w_theta = w_k by default for all measurements + /// angle_error = u_error / u_rated (1.0) = w_k /// /// @param block LHS(row, col), ie. LHS(row, row) /// @param rhs_block RHS(row) @@ -545,10 +548,10 @@ template class NewtonRaphsonSESolver { RealValue delta_theta{}; if (measured_values.has_angle_measurement(bus)) { delta_theta = RealValue{arg(measured_values.voltage(bus))} - RealValue{x_[bus].theta()}; - w_theta = RealTensor{1.0}; + w_theta = RealTensor{w_v}; } else if (bus == virtual_angle_measurement_bus && !measured_values.has_angle()) { delta_theta = arg(ComplexValue{1.0}) - RealValue{x_[bus].theta()}; - w_theta = RealTensor{1.0}; + w_theta = RealTensor{w_v}; } block.g_P_theta() += w_theta; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/observability.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/observability.hpp index 955af1b40..7ad7e4373 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/observability.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/observability.hpp @@ -32,16 +32,25 @@ std::tuple count_voltage_sensors(const Idx n_bus, const MeasuredValues // lower triangle part is always zero // for diagonal part, it will be one if there is bus injection // for upper triangle part, it will be one if there is branch flow sensor and the branch is fully connected +// return a pair of +// a vector of flow sensor count +// a boolean indicating if the system is possibly ill-conditioned template -std::vector count_flow_sensors(MeasuredValues const& measured_values, MathModelTopology const& topo, - YBusStructure const& y_bus_structure) { +std::pair, bool> count_flow_sensors(MeasuredValues const& measured_values, + MathModelTopology const& topo, + YBusStructure const& y_bus_structure) { Idx const n_bus{topo.n_bus()}; - std::vector flow_sensors(y_bus_structure.row_indptr.back(), 0); // initialize all to zero + std::pair, bool> result{}; + auto& [flow_sensors, possibly_ill_conditioned] = result; + flow_sensors.resize(y_bus_structure.row_indptr.back(), 0); // initialize all to zero + possibly_ill_conditioned = false; for (Idx row = 0; row != n_bus; ++row) { + bool has_at_least_one_sensor{false}; // lower triangle is ignored and kept as zero // diagonal for bus injection measurement if (measured_values.has_bus_injection(row)) { flow_sensors[y_bus_structure.bus_entry[row]] = 1; + has_at_least_one_sensor = true; } // upper triangle for branch flow measurement for (Idx ybus_index = y_bus_structure.bus_entry[row] + 1; ybus_index != y_bus_structure.row_indptr[row + 1]; @@ -57,13 +66,22 @@ std::vector count_flow_sensors(MeasuredValues const& measured_value if ((measured_values.has_branch_from(branch) || measured_values.has_branch_to(branch)) && topo.branch_bus_idx[branch][0] != -1 && topo.branch_bus_idx[branch][1] != -1) { flow_sensors[ybus_index] = 1; + has_at_least_one_sensor = true; break; } } } } + // check voltage sensor + if (measured_values.has_voltage(row) && measured_values.has_angle_measurement(row)) { + has_at_least_one_sensor = true; + } + // the system could be ill-conditioned if there is no flow sensor for one bus, except the last bus + if (!has_at_least_one_sensor && row != n_bus - 1) { + possibly_ill_conditioned = true; + } } - return flow_sensors; + return result; } // re-organize the flow sensor for radial grid without phasor measurement @@ -103,17 +121,27 @@ inline void assign_injection_sensor_radial(YBusStructure const& y_bus_structure, } // namespace detail +struct ObservabilityResult { + bool is_sufficiently_observable{false}; + bool is_possibly_ill_conditioned{false}; + constexpr bool use_perturbation() const { return is_possibly_ill_conditioned && is_sufficiently_observable; } +}; + template -inline void necessary_observability_check(MeasuredValues const& measured_values, MathModelTopology const& topo, - YBusStructure const& y_bus_structure) { +inline ObservabilityResult necessary_observability_check(MeasuredValues const& measured_values, + MathModelTopology const& topo, + YBusStructure const& y_bus_structure) { Idx const n_bus{topo.n_bus()}; + ObservabilityResult result{}; auto const [n_voltage_sensor, n_voltage_phasor_sensor] = detail::count_voltage_sensors(n_bus, measured_values); if (n_voltage_sensor < 1) { throw NotObservableError{"No voltage sensor found!\n"}; } - std::vector flow_sensors = detail::count_flow_sensors(measured_values, topo, y_bus_structure); + std::vector flow_sensors; + std::tie(flow_sensors, result.is_possibly_ill_conditioned) = + detail::count_flow_sensors(measured_values, topo, y_bus_structure); // count flow sensors, note we manually specify the intial value type to avoid overflow Idx const n_flow_sensor = std::reduce(flow_sensors.cbegin(), flow_sensors.cend(), Idx{}, std::plus{}); @@ -130,12 +158,16 @@ inline void necessary_observability_check(MeasuredValues const& measured_va if (topo.is_radial && n_voltage_phasor_sensor == 0) { detail::assign_injection_sensor_radial(y_bus_structure, flow_sensors); // count flow sensors again - Idx const n_flow_sensor_new = std::reduce(flow_sensors.cbegin(), flow_sensors.cend(), Idx{}, std::plus{}); - if (n_flow_sensor_new < n_bus - 1) { + if (Idx const n_flow_sensor_new = + std::reduce(flow_sensors.cbegin(), flow_sensors.cend(), Idx{}, std::plus{}); + n_flow_sensor_new < n_bus - 1) { throw NotObservableError{"The number of power sensors appears sufficient, but they are not independent " "enough. The system is still not observable.\n"}; } + result.is_sufficiently_observable = true; } + + return result; } } // namespace power_grid_model::math_solver diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_lu_solver.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_lu_solver.hpp index 494d5b2a0..5dd74d28f 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_lu_solver.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_lu_solver.hpp @@ -10,10 +10,138 @@ #include "../common/typing.hpp" #include +#include namespace power_grid_model::math_solver { -template struct sparse_lu_entry_trait; +constexpr double epsilon = std::numeric_limits::epsilon(); +constexpr double epsilon_perturbation = 1e-13; // perturbation threshold +constexpr double cap_back_error_denominator = 1e-4; // denominator for cap back error +constexpr double epsilon_sqrt = 1.49011745e-8; // sqrt(epsilon), sqrt does not have constexpr + +// perturb pivot if needed +// pass the value and abs_value by reference +// it will get modified if perturbation happens +// also has_pivot_perturbation will be updated if perturbation happens +template +inline void perturb_pivot_if_needed(double perturb_threshold, Scalar& value, double& abs_value, + bool& has_pivot_perturbation) { + if (abs_value < perturb_threshold) { + Scalar const scale = (abs_value == 0.0) ? Scalar{1.0} : (value / abs_value); + value = scale * perturb_threshold; + has_pivot_perturbation = true; + abs_value = perturb_threshold; + } +} + +// Dense LU factorization class +// The implementation of the Dense LU factorization was derived from the Eigen library +// https://gitlab.com/libeigen/eigen/-/blob/3.4/Eigen/src/LU/FullPivLU.h +// Copyright (C) 2006-2009 Benoit Jacob +// The original license remains: MPL-2.0 +// We modified the implementation to add the pivot perturbation +template class DenseLUFactor { + public: + using Scalar = typename Matrix::Scalar; + static constexpr Idx n_rows = Matrix::RowsAtCompileTime; + static constexpr Idx n_cols = Matrix::ColsAtCompileTime; + static_assert(std::in_range(n_rows)); + static_assert(n_rows == n_cols); + static constexpr int8_t size = n_rows; + using PermutationType = Eigen::PermutationMatrix; + using TranspositionVector = Eigen::Matrix; + struct BlockPerm { + PermutationType p; + PermutationType q; + }; + + // factorize in place + // put permutation in block_perm in place + // put pivot perturbation in has_pivot_perturbation in place + template + static void factorize_block_in_place(Eigen::MatrixBase&& matrix, BlockPerm& block_perm, + double perturb_threshold, bool use_pivot_perturbation, + bool& has_pivot_perturbation) + requires(std::same_as && rk2_tensor && + (Derived::RowsAtCompileTime == size) && (Derived::ColsAtCompileTime == size)) + { + TranspositionVector row_transpositions{}; + TranspositionVector col_transpositions{}; + double max_pivot{}; + + // main loop + for (int8_t pivot = 0; pivot != size; ++pivot) { + int row_biggest_eigen{}; + int col_biggest_eigen{}; + // find biggest score in the bottom right corner + double const biggest_score = matrix.bottomRightCorner(size - pivot, size - pivot) + .cwiseAbs2() + .maxCoeff(&row_biggest_eigen, &col_biggest_eigen); + // offset with pivot + auto const row_biggest = static_cast(row_biggest_eigen + pivot); + auto const col_biggest = static_cast(col_biggest_eigen + pivot); + assert(row_biggest_eigen + pivot < size); + assert(col_biggest_eigen + pivot < size); + + // check absolute singular matrix + if (biggest_score == 0.0 && !use_pivot_perturbation) { + // pivot perturbation not possible, cannot proceed + // set identity permutation and break the loop + for (int8_t remaining_rows_cols = pivot; remaining_rows_cols != size; ++remaining_rows_cols) { + row_transpositions[remaining_rows_cols] = remaining_rows_cols; + col_transpositions[remaining_rows_cols] = remaining_rows_cols; + } + break; + } + + // perturb pivot if needed + double abs_pivot = sqrt(biggest_score); + perturb_pivot_if_needed(perturb_threshold, matrix(row_biggest, col_biggest), abs_pivot, + has_pivot_perturbation); + max_pivot = std::max(max_pivot, abs_pivot); + + // swap rows and columns + row_transpositions[pivot] = row_biggest; + col_transpositions[pivot] = col_biggest; + if (pivot != row_biggest) { + matrix.row(pivot).swap(matrix.row(row_biggest)); + } + if (pivot != col_biggest) { + matrix.col(pivot).swap(matrix.col(col_biggest)); + } + + // use Gaussian elimination to calculate the bottom right corner + if (pivot < size - 1) { + // calculate the pivot column + matrix.col(pivot).tail(size - pivot - 1) /= matrix(pivot, pivot); + // calculate the bottom right corner + matrix.bottomRightCorner(size - pivot - 1, size - pivot - 1).noalias() -= + matrix.col(pivot).tail(size - pivot - 1) * matrix.row(pivot).tail(size - pivot - 1); + } + } + + // accumulate the permutation + block_perm.p.setIdentity(); + for (int8_t pivot = size - 1; pivot != -1; --pivot) { + block_perm.p.applyTranspositionOnTheRight(pivot, row_transpositions[pivot]); + } + block_perm.q.setIdentity(); + for (int8_t pivot = 0; pivot != size; ++pivot) { + block_perm.q.applyTranspositionOnTheRight(pivot, col_transpositions[pivot]); + } + + // throw SparseMatrixError if the matrix is ill-conditioned + // only check condition number if pivot perturbation is not used + double const pivot_threshold = has_pivot_perturbation ? 0.0 : epsilon * max_pivot; + for (int8_t pivot = 0; pivot != size; ++pivot) { + if (cabs(matrix(pivot, pivot)) < pivot_threshold || !is_normal(matrix(pivot, pivot))) { + throw SparseMatrixError{}; // can not specify error code + } + } + } +}; + +template struct sparse_lu_entry_trait; template concept scalar_value_lu = scalar_value && std::same_as && std::same_as; @@ -55,11 +183,8 @@ struct sparse_lu_entry_trait { static constexpr Idx block_size = Tensor::RowsAtCompileTime; using Scalar = typename Tensor::Scalar; using Matrix = Eigen::Matrix; - using LUFactor = Eigen::FullPivLU>; // LU decomposition with full pivoting in place - struct BlockPerm { - typename LUFactor::PermutationPType p; - typename LUFactor::PermutationQType q; - }; // Extract permutation matrices p and q from LUFactor + using LUFactor = DenseLUFactor; // LU decomposition with full pivoting in place + using BlockPerm = typename LUFactor::BlockPerm; // Extract permutation matrices p and q from LUFactor using BlockPermArray = std::vector; }; @@ -72,6 +197,7 @@ template class SparseLUSolver { using LUFactor = typename entry_trait::LUFactor; using BlockPerm = typename entry_trait::BlockPerm; using BlockPermArray = typename entry_trait::BlockPermArray; + static constexpr Idx max_iterative_refinement = 5; SparseLUSolver(std::shared_ptr const& row_indptr, // indptr including fill-ins std::shared_ptr col_indices, // indices including fill-ins @@ -86,8 +212,9 @@ template class SparseLUSolver { void prefactorize_and_solve(std::vector& data, // matrix data, factorize in-place BlockPermArray& block_perm_array, // pre-allocated permutation array, will be overwritten - std::vector const& rhs, std::vector& x) { - prefactorize(data, block_perm_array); + std::vector const& rhs, std::vector& x, + bool use_pivot_perturbation = false) { + prefactorize(data, block_perm_array, use_pivot_perturbation); // call solve with const method solve_with_prefactorized_matrix((std::vector const&)data, block_perm_array, rhs, x); } @@ -97,71 +224,10 @@ template class SparseLUSolver { solve_with_prefactorized_matrix(std::vector const& data, // pre-factoirzed data, const ref BlockPermArray const& block_perm_array, // pre-calculated permutation, const ref std::vector const& rhs, std::vector& x) { - // local reference - auto const& row_indptr = *row_indptr_; - auto const& col_indices = *col_indices_; - auto const& diag_lu = *diag_lu_; - auto const& lu_matrix = data; - - // forward substitution with L - for (Idx row = 0; row != size_; ++row) { - // permutation if needed - if constexpr (is_block) { - x[row] = (block_perm_array[row].p * rhs[row].matrix()).array(); - } else { - x[row] = rhs[row]; - } - - // loop all columns until diagonal - for (Idx l_idx = row_indptr[row]; l_idx < diag_lu[row]; ++l_idx) { - Idx const col = col_indices[l_idx]; - // never overshoot - assert(col < row); - // forward subtract - x[row] -= dot(lu_matrix[l_idx], x[col]); - } - // forward substitution inside block, for block matrix - if constexpr (is_block) { - XVector& xb = x[row]; - Tensor const& pivot = lu_matrix[diag_lu[row]]; - for (Idx br = 0; br < block_size; ++br) { - for (Idx bc = 0; bc < br; ++bc) { - xb(br) -= pivot(br, bc) * xb(bc); - } - } - } - } - - // backward substitution with U - for (Idx row = size_ - 1; row != -1; --row) { - // loop all columns from diagonal - for (Idx u_idx = row_indptr[row + 1] - 1; u_idx > diag_lu[row]; --u_idx) { - Idx const col = col_indices[u_idx]; - // always in upper diagonal - assert(col > row); - // backward subtract - x[row] -= dot(lu_matrix[u_idx], x[col]); - } - // solve the diagonal pivot - if constexpr (is_block) { - // backward substitution inside block - XVector& xb = x[row]; - Tensor const& pivot = lu_matrix[diag_lu[row]]; - for (Idx br = block_size - 1; br != -1; --br) { - for (Idx bc = block_size - 1; bc > br; --bc) { - xb(br) -= pivot(br, bc) * xb(bc); - } - xb(br) = xb(br) / pivot(br, br); - } - } else { - x[row] = x[row] / lu_matrix[diag_lu[row]]; - } - } - // restore permutation for block matrix - if constexpr (is_block) { - for (Idx row = 0; row != size_; ++row) { - x[row] = (block_perm_array[row].q * x[row].matrix()).array(); - } + if (has_pivot_perturbation_) { + solve_with_refinement(data, block_perm_array, rhs, x); + } else { + solve_once(data, block_perm_array, rhs, x); } } @@ -171,7 +237,14 @@ template class SparseLUSolver { // diagonals of U have values // fill-ins should be pre-allocated with zero // block permutation array should be pre-allocated - void prefactorize(std::vector& data, BlockPermArray& block_perm_array) { + void prefactorize(std::vector& data, BlockPermArray& block_perm_array, + bool use_pivot_perturbation = false) { + reset_matrix_cache(); + if (use_pivot_perturbation) { + initialize_pivot_perturbation(data); + } + double const perturb_threshold = epsilon_perturbation * matrix_norm_; + // local reference auto const& row_indptr = *row_indptr_; auto const& col_indices = *col_indices_; @@ -191,16 +264,20 @@ template class SparseLUSolver { // return reference to pivot permutation BlockPerm const& block_perm = [&]() -> std::conditional_t { if constexpr (is_block) { - LUFactor lu_factor(lu_matrix[pivot_idx]); - // set a low threshold, because state estimation can have large differences in eigen values - lu_factor.setThreshold(1e-100); - if (lu_factor.rank() < block_size) { - throw SparseMatrixError{}; - } + // use machine precision by default // record block permutation - block_perm_array[pivot_row_col] = {lu_factor.permutationP(), lu_factor.permutationQ()}; + LUFactor::factorize_block_in_place(lu_matrix[pivot_idx].matrix(), block_perm_array[pivot_row_col], + perturb_threshold, use_pivot_perturbation, + has_pivot_perturbation_); return block_perm_array[pivot_row_col]; } else { + if (use_pivot_perturbation) { + // use machine precision by default + // record pivot perturbation + double abs_pivot = cabs(lu_matrix[pivot_idx]); + perturb_pivot_if_needed(perturb_threshold, lu_matrix[pivot_idx], abs_pivot, + has_pivot_perturbation_); + } if (!is_normal(lu_matrix[pivot_idx])) { throw SparseMatrixError{}; } @@ -320,6 +397,10 @@ template class SparseLUSolver { // iterate column position for the pivot ++col_position_idx[pivot_row_col]; } + // if no pivot perturbation happened, reset cache + if (!has_pivot_perturbation_) { + reset_matrix_cache(); + } } private: @@ -328,6 +409,234 @@ template class SparseLUSolver { std::shared_ptr row_indptr_; std::shared_ptr col_indices_; std::shared_ptr diag_lu_; + // cache value for pivot perturbation for the factorize step + bool has_pivot_perturbation_{false}; + double matrix_norm_{}; + std::optional> original_matrix_; + // cache value for iterative refinement for the solve step + std::optional> dx_; + std::optional> residual_; + std::optional> rhs_; + + void solve_with_refinement(std::vector const& data, // pre-factoirzed data, const ref + BlockPermArray const& block_perm_array, // pre-calculated permutation, const ref + std::vector const& rhs, std::vector& x) { + // initialize refinement + initialize_refinement(rhs, x); + double backward_error{std::numeric_limits::max()}; + Idx num_iter{}; + // iterate until convergence + // convergence criteria is the same as the perturbation threshold + static constexpr double epsilon_converge = epsilon_perturbation; + while (backward_error > epsilon_converge) { + // check maximum iteration, including one initial run + if (num_iter++ == max_iterative_refinement + 1) { + throw SparseMatrixError{}; + } + // solve with residual (first time it is the b vector) + solve_once(data, block_perm_array, residual_.value(), dx_.value()); + // calculate backward error and then iterate x + backward_error = iterate_and_backward_error(x); + // calculate residual + calculate_residual(x); + } + // reset refinement cache + reset_refinement_cache(); + } + + void reset_refinement_cache() { + dx_.reset(); + residual_.reset(); + rhs_.reset(); + } + + void initialize_refinement(std::vector const& rhs, std::vector& x) { + // save a copy of rhs + rhs_ = rhs; + // initialize x to zero + for (Idx row = 0; row != size_; ++row) { + if constexpr (is_block) { + x[row] = XVector::Zero(); + } else { + x[row] = 0.0; + } + } + // initialize residual to rhs + // because r = b - A * x = b - 0 = b + residual_ = rhs_; + // initialize dx to zero + // pre-allocate memory + dx_ = x; + } + + void calculate_residual(std::vector const& x) { + auto const& row_indptr = *row_indptr_; + auto const& col_indices = *col_indices_; + auto const& original_matrix = original_matrix_.value(); + auto const& rhs = rhs_.value(); + auto& residual = residual_.value(); + // calculate residual + for (Idx row = 0; row != size_; ++row) { + residual[row] = rhs[row]; + // loop all columns + for (Idx idx = row_indptr[row]; idx != row_indptr[row + 1]; ++idx) { + // subtract + residual[row] -= dot(original_matrix[idx], x[col_indices[idx]]); + } + } + } + + double iterate_and_backward_error(std::vector& x) { + auto const& row_indptr = *row_indptr_; + auto const& col_indices = *col_indices_; + auto const& original_matrix = original_matrix_.value(); + auto const& rhs = rhs_.value(); + auto const& residual = residual_.value(); + auto const& dx = dx_.value(); + using RealValueType = std::conditional_t, double>; + std::vector all_denominators(size_); + double max_denominator{}; + + // calculate denominator and get the max value + for (Idx row = 0; row != size_; ++row) { + // error denominator by |rhs| + RealValueType denominator = cabs(rhs[row]); + // then append |A| * |x| + for (Idx idx = row_indptr[row]; idx != row_indptr[row + 1]; ++idx) { + denominator += dot(cabs(original_matrix[idx]), cabs(x[col_indices[idx]])); + } + all_denominators[row] = denominator; + max_denominator = std::max(max_denominator, max_val(denominator)); + } + // cap min denominator + double const min_denominator = cap_back_error_denominator * max_denominator; + + // calculate backward error and then iterate x + double max_berr{}; + for (Idx row = 0; row != size_; ++row) { + RealValueType const numerator = cabs(residual[row]); + // cap denominator to min_denominator + if constexpr (is_block) { + for (Idx br = 0; br != block_size; ++br) { + all_denominators[row](br) = std::max(all_denominators[row](br), min_denominator); + } + } else { + all_denominators[row] = std::max(all_denominators[row], min_denominator); + } + // piecewise backward error and get max + RealValueType const berr = numerator / all_denominators[row]; + max_berr = std::max(max_berr, max_val(berr)); + // iterate x + x[row] += dx[row]; + } + return max_berr; + } + + void initialize_pivot_perturbation(std::vector const& data) { + // save a copy of original matrix + original_matrix_ = data; + // calculate the block-wise non-diagonal infinite norm of the matrix + // that is: + // 1. calculate the infinite norm of each individual block + // 2. sum all norms of the blocks per row, except the diagonal block + // 3. take the maximum of all the sums + matrix_norm_ = 0.0; + auto const& row_indptr = *row_indptr_; + auto const& col_indices = *col_indices_; + for (Idx row = 0; row != size_; ++row) { + // calculate the sum of the norms of the blocks in the row + double row_norm = 0.0; + for (Idx idx = row_indptr[row]; idx != row_indptr[row + 1]; ++idx) { + // skip diagonal + if (col_indices[idx] == row) { + continue; + } + if constexpr (is_block) { + row_norm += cabs(data[idx]).rowwise().sum().maxCoeff(); + } else { + row_norm += cabs(data[idx]); + } + } + matrix_norm_ = std::max(matrix_norm_, row_norm); + } + } + + void reset_matrix_cache() { + has_pivot_perturbation_ = false; + matrix_norm_ = 0.0; + original_matrix_.reset(); + } + + void solve_once(std::vector const& data, // pre-factoirzed data, const ref + BlockPermArray const& block_perm_array, // pre-calculated permutation, const ref + std::vector const& rhs, std::vector& x) const { + // local reference + auto const& row_indptr = *row_indptr_; + auto const& col_indices = *col_indices_; + auto const& diag_lu = *diag_lu_; + auto const& lu_matrix = data; + + // forward substitution with L + for (Idx row = 0; row != size_; ++row) { + // permutation if needed + if constexpr (is_block) { + x[row] = (block_perm_array[row].p * rhs[row].matrix()).array(); + } else { + x[row] = rhs[row]; + } + + // loop all columns until diagonal + for (Idx l_idx = row_indptr[row]; l_idx < diag_lu[row]; ++l_idx) { + Idx const col = col_indices[l_idx]; + // never overshoot + assert(col < row); + // forward subtract + x[row] -= dot(lu_matrix[l_idx], x[col]); + } + // forward substitution inside block, for block matrix + if constexpr (is_block) { + XVector& xb = x[row]; + Tensor const& pivot = lu_matrix[diag_lu[row]]; + for (Idx br = 0; br < block_size; ++br) { + for (Idx bc = 0; bc < br; ++bc) { + xb(br) -= pivot(br, bc) * xb(bc); + } + } + } + } + + // backward substitution with U + for (Idx row = size_ - 1; row != -1; --row) { + // loop all columns from diagonal + for (Idx u_idx = row_indptr[row + 1] - 1; u_idx > diag_lu[row]; --u_idx) { + Idx const col = col_indices[u_idx]; + // always in upper diagonal + assert(col > row); + // backward subtract + x[row] -= dot(lu_matrix[u_idx], x[col]); + } + // solve the diagonal pivot + if constexpr (is_block) { + // backward substitution inside block + XVector& xb = x[row]; + Tensor const& pivot = lu_matrix[diag_lu[row]]; + for (Idx br = block_size - 1; br != -1; --br) { + for (Idx bc = block_size - 1; bc > br; --bc) { + xb(br) -= pivot(br, bc) * xb(bc); + } + xb(br) = xb(br) / pivot(br, br); + } + } else { + x[row] = x[row] / lu_matrix[diag_lu[row]]; + } + } + // restore permutation for block matrix + if constexpr (is_block) { + for (Idx row = 0; row != size_; ++row) { + x[row] = (block_perm_array[row].q * x[row].matrix()).array(); + } + } + } }; } // namespace power_grid_model::math_solver diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp index 6c79fa572..e78c1bcc5 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp @@ -959,13 +959,14 @@ class TapPositionOptimizerImpl, StateCalculator, adjust_transformer(regulator, state, result, update_data, search, options) || tap_changed; } if (tap_changed) { + iterations_per_rank[rank_index + 1] = 0; + ++iterations_per_rank[rank_index]; break; } - iterations_per_rank[++rank_index] = 0; // NOSONAR + ++rank_index; } if (tap_changed) { - if (static_cast(++iterations_per_rank[rank_index]) > - 2 * max_tap_ranges_per_rank[rank_index]) { + if (static_cast(iterations_per_rank[rank_index]) > 2 * max_tap_ranges_per_rank[rank_index]) { throw MaxIterationReached{"TapPositionOptimizer::iterate"}; } update_state(update_data); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 5968ebfcb..96f49d225 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -429,8 +429,6 @@ class Topology { } } - static constexpr auto include_all = [](Idx) { return true; }; - // proxy class to find the coupled object in math model in the coupling process to a single type object // given a particular component index struct SingleTypeObjectFinder { @@ -481,7 +479,7 @@ class Topology { // The coupling element should be pre-allocated in coupling // Only connect the component if include(component_i) returns true template + typename ObjectFinder = SingleTypeObjectFinder, typename Predicate = IncludeAll> requires std::invocable, MathModelTopology&> && grouped_idx_vector_type< std::remove_reference_t>> diff --git a/pyproject.toml b/pyproject.toml index 7343ab1ee..9e034a2f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Operating System :: MacOS", "Topic :: Scientific/Engineering :: Physics", ] -requires-python = ">=3.10" +requires-python = ">=3.11" dependencies = ["numpy>=1.21.0"] dynamic = ["version"] @@ -52,6 +52,7 @@ doc = [ "numpydoc", "pandas", "gitpython", + "pylint", ] [project.urls] @@ -87,7 +88,7 @@ xfail_strict = true [tool.black] line-length = 120 -target-version = ['py310'] +target-version = ['py311'] [tool.isort] profile = "black" diff --git a/src/power_grid_model/_core/power_grid_dataset.py b/src/power_grid_model/_core/power_grid_dataset.py index 92285cb8d..28a5549f9 100644 --- a/src/power_grid_model/_core/power_grid_dataset.py +++ b/src/power_grid_model/_core/power_grid_dataset.py @@ -6,7 +6,7 @@ Power grid model raw dataset handler """ -from typing import Any, Mapping +from typing import Any, Mapping, cast from power_grid_model._core.buffer_handling import ( BufferProperties, @@ -26,8 +26,16 @@ power_grid_core as pgc, ) from power_grid_model._core.power_grid_meta import ComponentMetaData, DatasetMetaData, power_grid_meta_data -from power_grid_model._utils import get_dataset_type, is_columnar, is_nan_or_equivalent, process_data_filter -from power_grid_model.data_types import AttributeType, ComponentData, Dataset +from power_grid_model._utils import get_dataset_type, is_columnar, is_nan_or_equivalent, is_sparse, process_data_filter +from power_grid_model.data_types import ( + AttributeType, + ColumnarData, + ComponentData, + Dataset, + DenseBatchColumnarData, + SingleColumnarData, + SparseBatchColumnarData, +) from power_grid_model.enum import ComponentAttributeFilterOptions from power_grid_model.typing import ComponentAttributeMapping, _ComponentAttributeMappingDict @@ -455,22 +463,25 @@ def _get_buffer_properties(self, info: CDatasetInfo) -> Mapping[ComponentType, B if component in self._data_filter } - def _filter_attributes(self, attributes): + def _filter_attributes(self, buffer: ColumnarData): + if is_sparse(buffer): + attributes = cast(SparseBatchColumnarData, buffer)["data"] + else: + attributes = cast(SingleColumnarData | DenseBatchColumnarData, buffer) + keys_to_remove = [] for attr, array in attributes.items(): - if is_columnar(array): - continue if is_nan_or_equivalent(array): keys_to_remove.append(attr) for key in keys_to_remove: del attributes[key] def _filter_with_mapping(self): - for component_type, attributes in self._data.items(): + for component_type, component_buffer in self._data.items(): if component_type in self._data_filter: filter_option = self._data_filter[component_type] - if filter_option is ComponentAttributeFilterOptions.relevant: - self._filter_attributes(attributes) + if filter_option is ComponentAttributeFilterOptions.relevant and is_columnar(component_buffer): + self._filter_attributes(component_buffer) def _post_filtering(self): if isinstance(self._data_filter, dict): diff --git a/src/power_grid_model/_core/power_grid_model.py b/src/power_grid_model/_core/power_grid_model.py index d4ce2eff1..424fddda4 100644 --- a/src/power_grid_model/_core/power_grid_model.py +++ b/src/power_grid_model/_core/power_grid_model.py @@ -51,7 +51,9 @@ class PowerGridModel: @property def batch_error(self) -> PowerGridBatchError | None: """ - Get the batch error object, if present + Get the batch error object, if present, after a batch calculation with errors. + + Also works when continue_on_batch_error was set to True during the calculation. Returns: Batch error object, or None @@ -474,8 +476,9 @@ def calculate_power_flow( - None: Row based data for the specified component types. - ComponentAttributeFilterOptions: Columnar data for the specified component types. - set[str] | list[str]: Columnar data for the specified component types and attributes. - continue_on_batch_error (bool, optional): Continue the program (instead of throwing error) if some - scenarios fail. + continue_on_batch_error (bool, optional): + Continue the program (instead of throwing error) if some scenarios fail. + You can still retrieve the errors and succeeded/failed scenarios via the batch_error. decode_error (bool, optional): Decode error messages to their derived types if possible. @@ -568,8 +571,9 @@ def calculate_state_estimation( - None: Row based data for the specified component types. - ComponentAttributeFilterOptions: Columnar data for the specified component types. - set[str] | list[str]: Columnar data for the specified component types and attributes. - continue_on_batch_error (bool, optional): Continue the program (instead of throwing error) if some - scenarios fail. + continue_on_batch_error (bool, optional): + Continue the program (instead of throwing error) if some scenarios fail. + You can still retrieve the errors and succeeded/failed scenarios via the batch_error. decode_error (bool, optional): Decode error messages to their derived types if possible. @@ -653,6 +657,7 @@ def calculate_short_circuit( - set[str] | list[str]: Columnar data for the specified component types and attributes. continue_on_batch_error (bool, optional): Continue the program (instead of throwing error) if some scenarios fail. + You can still retrieve the errors and succeeded/failed scenarios via the batch_error. decode_error (bool, optional): Decode error messages to their derived types if possible. short_circuit_voltage_scaling ({ShortCircuitVoltageSaling, str}, optional): diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index a0144cd73..2ea73e4a2 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -158,7 +158,6 @@ def validate_batch_data( batch_errors = input_errors + id_errors if not id_errors: - batch_errors = input_errors merged_data = _update_input_data(input_data_copy, row_update_data) batch_errors += validate_required_values(merged_data, calculation_type, symmetric) batch_errors += validate_values(merged_data, calculation_type) diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index 53bdeb029..12c4d801a 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -48,6 +48,7 @@ set(PROJECT_SOURCES "test_math_solver_se_newton_raphson.cpp" "test_math_solver_se_iterative_linear.cpp" "test_math_solver_sc.cpp" + "test_current_sensor.cpp" ) add_executable(power_grid_model_unit_tests ${PROJECT_SOURCES}) diff --git a/tests/cpp_unit_tests/test_current_sensor.cpp b/tests/cpp_unit_tests/test_current_sensor.cpp new file mode 100644 index 000000000..7b8d0b1a3 --- /dev/null +++ b/tests/cpp_unit_tests/test_current_sensor.cpp @@ -0,0 +1,236 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include + +namespace power_grid_model { +namespace { +auto const r_nan = RealValue{nan}; + +void check_nan_preserving_equality(std::floating_point auto actual, std::floating_point auto expected) { + if (is_nan(expected)) { + is_nan(actual); + } else { + CHECK(actual == doctest::Approx(expected)); + } +} +void check_nan_preserving_equality(RealValue const& actual, RealValue const& expected) { + for (auto i : {0, 1, 2}) { + CAPTURE(i); + check_nan_preserving_equality(actual(i), expected(i)); + } +} +} // namespace + +TEST_CASE("Test current sensor") { + SUBCASE("Symmetric Current Sensor") { + for (auto const terminal_type : + {MeasuredTerminalType::branch_from, MeasuredTerminalType::branch_to, MeasuredTerminalType::branch3_1, + MeasuredTerminalType::branch3_2, MeasuredTerminalType::branch3_3}) { + CAPTURE(terminal_type); + + CurrentSensorInput sym_current_sensor_input{}; + sym_current_sensor_input.id = 0; + sym_current_sensor_input.measured_object = 1; + sym_current_sensor_input.measured_terminal_type = terminal_type; + sym_current_sensor_input.angle_measurement_type = AngleMeasurementType::local; + sym_current_sensor_input.i_sigma = 1.0; + sym_current_sensor_input.i_measured = 1.0 * 1e3; + sym_current_sensor_input.i_angle_measured = 0.0; + sym_current_sensor_input.i_angle_sigma = nan; + + double const u_rated = 10.0e3; + double const base_current = base_power_3p / u_rated / sqrt3; + + ComplexValue const i_sym = (1.0 * 1e3 + 1i * 0.0) / base_current; + ComplexValue const i_asym = i_sym * RealValue{1.0}; + + CurrentSensor const sym_current_sensor{sym_current_sensor_input, u_rated}; + + CurrentSensorCalcParam sym_sensor_param = sym_current_sensor.calc_param(); + CurrentSensorCalcParam asym_sensor_param = sym_current_sensor.calc_param(); + + CurrentSensorOutput const sym_sensor_output = + sym_current_sensor.get_output(i_sym); + CurrentSensorOutput sym_sensor_output_asym_param = + sym_current_sensor.get_output(i_asym); + + // Check symmetric sensor output for symmetric parameters + CHECK(sym_sensor_param.angle_measurement_type == AngleMeasurementType::local); + CHECK(sym_sensor_param.i_real_variance == doctest::Approx(0.0)); + CHECK(sym_sensor_param.i_imag_variance == doctest::Approx(0.0)); + CHECK(real(sym_sensor_param.value) == doctest::Approx(0.0)); + CHECK(imag(sym_sensor_param.value) == doctest::Approx(0.0)); + + CHECK(is_nan(sym_sensor_output.id)); + CHECK(is_nan(sym_sensor_output.energized)); + CHECK(is_nan(sym_sensor_output.i_residual)); + CHECK(is_nan(sym_sensor_output.i_angle_residual)); + + // Check symmetric sensor output for asymmetric parameters + CHECK(asym_sensor_param.i_real_variance == doctest::Approx(0.0)); + CHECK(asym_sensor_param.i_imag_variance == doctest::Approx(0.0)); + CHECK(real(asym_sensor_param.value[0]) == doctest::Approx(0.0)); + CHECK(imag(asym_sensor_param.value[1]) == doctest::Approx(0.0)); + + CHECK(is_nan(sym_sensor_output_asym_param.id)); + CHECK(is_nan(sym_sensor_output_asym_param.energized)); + CHECK(is_nan(sym_sensor_output_asym_param.i_residual[0])); + CHECK(is_nan(sym_sensor_output_asym_param.i_angle_residual[1])); + + CHECK(sym_current_sensor.get_terminal_type() == terminal_type); + + CHECK(sym_current_sensor.get_angle_measurement_type() == AngleMeasurementType::local); + } + SUBCASE("Wrong measured terminal type") { + for (auto const terminal_type : + {MeasuredTerminalType::source, MeasuredTerminalType::shunt, MeasuredTerminalType::load, + MeasuredTerminalType::generator, MeasuredTerminalType::node}) { + CHECK_THROWS_AS((CurrentSensor{ + {1, 1, terminal_type, AngleMeasurementType::local, 1.0, 1.0, 1.0, 1.0}, 1.0}), + InvalidMeasuredTerminalType); + } + } + } + SUBCASE("Update inverse - sym") { + constexpr auto i_measured = 1.0; + constexpr auto i_angle_measured = 2.0; + constexpr auto i_sigma = 3.0; + constexpr auto i_angle_sigma = 4.0; + constexpr auto u_rated = 10.0e3; + CurrentSensor const current_sensor{{1, 1, MeasuredTerminalType::branch3_1, + AngleMeasurementType::local, i_sigma, i_angle_sigma, + i_measured, i_angle_measured}, + u_rated}; + + CurrentSensorUpdate cs_update{1, nan, nan, nan, nan}; + auto expected = cs_update; + + SUBCASE("Identical") { + // default values + } + + SUBCASE("i_sigma") { + SUBCASE("same") { cs_update.i_sigma = i_sigma; } + SUBCASE("different") { cs_update.i_sigma = 0.0; } + expected.i_sigma = i_sigma; + } + + SUBCASE("i_angle_sigma") { + SUBCASE("same") { cs_update.i_angle_sigma = i_angle_sigma; } + SUBCASE("different") { cs_update.i_angle_sigma = 0.0; } + expected.i_angle_sigma = i_angle_sigma; + } + + SUBCASE("i_measured") { + SUBCASE("same") { cs_update.i_measured = i_measured; } + SUBCASE("different") { cs_update.i_measured = 0.0; } + expected.i_measured = i_measured; + } + + SUBCASE("i_angle_measured") { + SUBCASE("same") { cs_update.i_angle_measured = i_angle_measured; } + SUBCASE("different") { cs_update.i_angle_measured = 0.0; } + expected.i_angle_measured = i_angle_measured; + } + + SUBCASE("multiple") { + cs_update.i_sigma = 0.0; + cs_update.i_angle_sigma = 0.0; + cs_update.i_measured = 0.0; + cs_update.i_angle_measured = 0.0; + expected.i_sigma = i_sigma; + expected.i_angle_sigma = i_angle_sigma; + expected.i_measured = i_measured; + expected.i_angle_measured = i_angle_measured; + } + + auto const inv = current_sensor.inverse(cs_update); + + CHECK(inv.id == expected.id); + check_nan_preserving_equality(inv.i_sigma, expected.i_sigma); + check_nan_preserving_equality(inv.i_angle_sigma, expected.i_angle_sigma); + check_nan_preserving_equality(inv.i_measured, expected.i_measured); + check_nan_preserving_equality(inv.i_angle_measured, expected.i_angle_measured); + } + + SUBCASE("Update inverse - asym") { + RealValue i_measured = {1.0, 2.0, 3.0}; + RealValue i_angle_measured = {4.0, 5.0, 6.0}; + constexpr auto i_sigma = 3.0; + constexpr auto i_angle_sigma = 4.0; + constexpr auto u_rated = 10.0e3; + MeasuredTerminalType const measured_terminal_type = MeasuredTerminalType::branch_from; + + CurrentSensorUpdate cs_update{1, nan, nan, r_nan, r_nan}; + auto expected = cs_update; + + SUBCASE("Identical") { + // default values + } + + SUBCASE("i_sigma") { + SUBCASE("same") { cs_update.i_sigma = i_sigma; } + SUBCASE("different") { cs_update.i_sigma = 0.0; } + expected.i_sigma = i_sigma; + } + + SUBCASE("i_angle_sigma") { + SUBCASE("same") { cs_update.i_angle_sigma = i_angle_sigma; } + SUBCASE("different") { cs_update.i_angle_sigma = 0.0; } + expected.i_angle_sigma = i_angle_sigma; + } + + SUBCASE("i_measured") { + SUBCASE("same") { cs_update.i_measured = i_measured; } + SUBCASE("1 different") { + cs_update.i_measured = {0.0, nan, nan}; + expected.i_measured = {i_measured(0), nan, nan}; + } + SUBCASE("all different") { + cs_update.i_measured = {0.0, 0.1, 0.2}; + expected.i_measured = i_measured; + } + } + + SUBCASE("i_angle_measured") { + SUBCASE("same") { cs_update.i_angle_measured = i_angle_measured; } + SUBCASE("1 different") { + cs_update.i_angle_measured = {0.0, nan, nan}; + expected.i_angle_measured = {i_angle_measured(0), nan, nan}; + } + SUBCASE("all different") { + cs_update.i_angle_measured = {0.0, 0.1, 0.2}; + expected.i_angle_measured = i_angle_measured; + } + } + + SUBCASE("multiple") { + cs_update.i_sigma = 0.0; + cs_update.i_angle_sigma = 0.1; + cs_update.i_measured = {0.0, 0.2, 0.4}; + cs_update.i_angle_measured = {0.0, 0.3, 0.6}; + expected.i_sigma = i_sigma; + expected.i_angle_sigma = i_angle_sigma; + expected.i_measured = i_measured; + expected.i_angle_measured = i_angle_measured; + } + + CurrentSensor const current_sensor{{1, 1, measured_terminal_type, AngleMeasurementType::local, + i_sigma, i_angle_sigma, i_measured, i_angle_measured}, + u_rated}; + + auto const inv = current_sensor.inverse(cs_update); + + CHECK(inv.id == expected.id); + check_nan_preserving_equality(inv.i_sigma, expected.i_sigma); + check_nan_preserving_equality(inv.i_angle_sigma, expected.i_angle_sigma); + check_nan_preserving_equality(inv.i_measured, expected.i_measured); + check_nan_preserving_equality(inv.i_angle_measured, expected.i_angle_measured); + } +} + +} // namespace power_grid_model diff --git a/tests/cpp_unit_tests/test_power_sensor.cpp b/tests/cpp_unit_tests/test_power_sensor.cpp index f051c6e7a..ba8b82806 100644 --- a/tests/cpp_unit_tests/test_power_sensor.cpp +++ b/tests/cpp_unit_tests/test_power_sensor.cpp @@ -572,21 +572,21 @@ TEST_CASE("Test power sensor") { } SUBCASE("Construction and update") { - PowerSensorInput sym_power_sensor_input{.id = 7, - .measured_object = 3, - .measured_terminal_type = - MeasuredTerminalType::branch_from, - .power_sigma = 269258.24035672517, - .p_measured = -2e5, - .q_measured = -1e6, - .p_sigma = 2.5e5, - .q_sigma = 1e5}; - PowerSensorUpdate sym_power_sensor_update{.id = 7, - .power_sigma = sym_power_sensor_input.power_sigma, - .p_measured = sym_power_sensor_input.p_measured, - .q_measured = sym_power_sensor_input.q_measured, - .p_sigma = sym_power_sensor_input.p_sigma, - .q_sigma = sym_power_sensor_input.q_sigma}; + PowerSensorInput const sym_power_sensor_input{.id = 7, + .measured_object = 3, + .measured_terminal_type = + MeasuredTerminalType::branch_from, + .power_sigma = 269258.24035672517, + .p_measured = -2e5, + .q_measured = -1e6, + .p_sigma = 2.5e5, + .q_sigma = 1e5}; + PowerSensorUpdate const sym_power_sensor_update{.id = 7, + .power_sigma = sym_power_sensor_input.power_sigma, + .p_measured = sym_power_sensor_input.p_measured, + .q_measured = sym_power_sensor_input.q_measured, + .p_sigma = sym_power_sensor_input.p_sigma, + .q_sigma = sym_power_sensor_input.q_sigma}; SymPowerSensor sym_power_sensor{sym_power_sensor_input}; auto const orig_calc_param = sym_power_sensor.calc_param(); diff --git a/tests/cpp_unit_tests/test_sparse_lu_solver.cpp b/tests/cpp_unit_tests/test_sparse_lu_solver.cpp index af9542f8f..45f9a854b 100644 --- a/tests/cpp_unit_tests/test_sparse_lu_solver.cpp +++ b/tests/cpp_unit_tests/test_sparse_lu_solver.cpp @@ -128,4 +128,72 @@ TEST_CASE("Test Sparse LU solver") { } } +TEST_CASE("LU solver with ill-conditioned system") { + // test with ill-conditioned matrix if we do not do numerical pivoting + // 4*4 matrix, or 2*2 with 2*2 blocks + // [ [ [ + // 0 0 0 -1 8 0 + // 0 -1 0 0 0 0 + // 0 0 5 1 * 10 = 50 + // -1 0 1 -9 0 2 + // ] ] ] + // + + SUBCASE("Scalar variant") { + auto row_indptr = std::make_shared(IdxVector{0, 4, 8, 12, 16}); + auto col_indices = std::make_shared(IdxVector{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}); + auto diag_lu = std::make_shared(IdxVector{0, 5, 10, 15}); + auto data = std::vector{ + 0, 0, 0, -1, // row 0 + 0, -1, 0, 0, // row 1 + 0, 0, 5, 1, // row 2 + -1, 0, 1, -9 // row 3 + }; + auto const rhs = std::vector{0, 0, 50, 2}; + auto const x_ref = std::vector{8, 0, 10, 0}; + auto x = std::vector(4, 0.0); + + SparseLUSolver solver{row_indptr, col_indices, diag_lu}; + Idx perm{}; + + SUBCASE("Error without perturbation") { + CHECK_THROWS_AS(solver.prefactorize(data, perm, false), SparseMatrixError); + } + + SUBCASE("Success with perturbation") { + CHECK_NOTHROW(solver.prefactorize(data, perm, true)); + solver.solve_with_prefactorized_matrix(data, perm, rhs, x); + check_result(x, x_ref); + } + } + + SUBCASE("Block variant") { + auto row_indptr = std::make_shared(IdxVector{0, 2, 4}); + auto col_indices = std::make_shared(IdxVector{0, 1, 0, 1}); + auto diag_lu = std::make_shared(IdxVector{0, 3}); + auto data = std::vector{ + {{0, 0}, {0, -1}}, // 0, 0 + {{0, -1}, {0, 0}}, // 0, 1 + {{0, 0}, {-1, 0}}, // 1, 0 + {{5, 1}, {1, -9}}, // 1, 1 + }; + auto const rhs = std::vector{{0, 0}, {50, 2}}; + auto const x_ref = std::vector{{8, 0}, {10, 0}}; + auto x = std::vector(2, Array::Zero()); + auto block_perm = std::vector::BlockPerm>(2); + + SparseLUSolver solver{row_indptr, col_indices, diag_lu}; + + SUBCASE("Error without perturbation") { + CHECK_THROWS_AS(solver.prefactorize(data, block_perm, false), SparseMatrixError); + } + + SUBCASE("Success with perturbation") { + CHECK_NOTHROW(solver.prefactorize(data, block_perm, true)); + solver.solve_with_prefactorized_matrix(data, block_perm, rhs, x); + check_result(x, x_ref); + } + } +} + } // namespace power_grid_model::math_solver diff --git a/tests/cpp_unit_tests/test_voltage_sensor.cpp b/tests/cpp_unit_tests/test_voltage_sensor.cpp index 432181d56..e01d9aada 100644 --- a/tests/cpp_unit_tests/test_voltage_sensor.cpp +++ b/tests/cpp_unit_tests/test_voltage_sensor.cpp @@ -497,13 +497,13 @@ TEST_CASE("Test voltage sensor") { } SUBCASE("Construction and update") { - VoltageSensorInput sym_voltage_sensor_input{ + VoltageSensorInput const sym_voltage_sensor_input{ .id = 7, .measured_object = 3, .u_sigma = 1.0, .u_measured = 25000, .u_angle_measured = -0.2}; - VoltageSensorUpdate sym_voltage_sensor_update{.id = 7, - .u_sigma = sym_voltage_sensor_input.u_sigma, - .u_measured = sym_voltage_sensor_input.u_measured, - .u_angle_measured = - sym_voltage_sensor_input.u_angle_measured}; + VoltageSensorUpdate const sym_voltage_sensor_update{ + .id = 7, + .u_sigma = sym_voltage_sensor_input.u_sigma, + .u_measured = sym_voltage_sensor_input.u_measured, + .u_angle_measured = sym_voltage_sensor_input.u_angle_measured}; SymVoltageSensor sym_voltage_sensor{sym_voltage_sensor_input, 31250}; auto const orig_calc_param = sym_voltage_sensor.calc_param(); diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json new file mode 100644 index 000000000..3b748a1cc --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json @@ -0,0 +1,59 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000}, + {"id": 3, "u_rated": 10000}, + {"id": 4, "u_rated": 10000}, + {"id": 5, "u_rated": 10000}, + {"id": 6, "u_rated": 10000}, + {"id": 7, "u_rated": 400}, + {"id": 8, "u_rated": 400}, + {"id": 9, "u_rated": 400}, + {"id": 10, "u_rated": 400} + ], + "line": [ + {"id": 11, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 12, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.6, "c1": 0, "tan1": 0}, + {"id": 13, "from_node": 3, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 14, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "r1": 0.003, "x1": 0.3, "c1": 0, "tan1": 0}, + {"id": 15, "from_node": 7, "to_node": 9, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 16, "from_node": 8, "to_node": 9, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.6, "c1": 0, "tan1": 0} + ], + "transformer": [ + {"id": 17, "from_node": 1, "to_node": 3, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 100}, + {"id": 18, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 100}, + {"id": 19, "from_node": 5, "to_node": 7, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20}, + {"id": 20, "from_node": 6, "to_node": 8, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20}, + {"id": 21, "from_node": 9, "to_node": 10, "from_status": 1, "to_status": 1, "u1": 400, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20} + ], + "source": [ + {"id": 22, "node": 0, "status": 1, "u_ref": 1} + ], + "sym_load": [ + {"id": 23, "node": 0, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 24, "node": 1, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 25, "node": 2, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 26, "node": 3, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 27, "node": 4, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 28, "node": 5, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 29, "node": 6, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 30, "node": 7, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 31, "node": 8, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 32, "node": 9, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 33, "node": 10, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000} + ], + "transformer_tap_regulator": [ + {"id": 34, "regulated_object": 17, "status": 1, "control_side": 1, "u_set": 10000, "u_band": 300}, + {"id": 35, "regulated_object": 18, "status": 1, "control_side": 1, "u_set": 10000, "u_band": 300}, + {"id": 36, "regulated_object": 19, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5}, + {"id": 37, "regulated_object": 20, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5}, + {"id": 38, "regulated_object": 21, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json new file mode 100644 index 000000000..c3482bcef --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json @@ -0,0 +1,10 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "any_valid_tap", + "rtol": 1e-05, + "atol": 1e-05, + "fail": { + "raises": "MaxIterationReached", + "reason": "TapPositionOptimizer::iterate" + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json new file mode 100644 index 000000000..682b959f0 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json @@ -0,0 +1,7 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": {} +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/asym_output.json new file mode 100644 index 000000000..249bb95ce --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/asym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9947061877982076, 0.9947061877982079, 0.9947061877982095], "u": [5742.938852898817, 5742.938852898817, 5742.938852898827], "u_angle": [-0.007066394337766698, -2.101461496730962, 2.087328708055429], "p": [501035.9177205215, 501035.9177204648, 501035.9177204662], "q": [301035.9177205401, 301035.9177205265, 301035.9177205166]}, + {"id": 1, "energized": 1, "u_pu": [0.9922873497821686, 0.992287349782169, 0.9922873497821706], "u": [5728.973685101953, 5728.973685101956, 5728.973685101965], "u_angle": [-0.007674275944599745, -2.102069378337795, 2.086720826448596], "p": [-499999.9999999938, -499999.9999999373, -499999.9999999386], "q": [-300000.0000000124, -299999.9999999988, -299999.999999989]} + ], + "line": [ + {"id": 2, "energized": 1, "p_from": [501035.9177205215, 501035.9177204648, 501035.9177204662], "q_from": [301035.9177205401, 301035.9177205265, 301035.9177205166], "i_from": [101.7800432564134, 101.7800432564037, 101.7800432564029], "s_from": [584516.5648669788, 584516.5648669231, 584516.5648669192], "p_to": [-499999.9999999938, -499999.9999999373, -499999.9999999386], "q_to": [-300000.0000000124, -299999.9999999988, -299999.999999989], "i_to": [101.7800432564134, 101.7800432564037, 101.7800432564029], "s_to": [583095.1894845311, 583095.1894844756, 583095.1894844718]} + ], + "source": [ + {"id": 3, "energized": 1, "p": [501035.9177205215, 501035.9177204648, 501035.9177204662], "q": [301035.9177205402, 301035.9177205265, 301035.9177205166], "i": [101.7800432564134, 101.7800432564037, 101.7800432564029], "s": [584516.5648669788, 584516.5648669231, 584516.5648669192], "pf": [0.8571800147948665, 0.8571800147948513, 0.8571800147948594]} + ], + "sym_load": [ + {"id": 4, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7800432564133, 101.7800432564132, 101.780043256413], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/leaf-without-power-sensor/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/asym_output.json.license similarity index 100% rename from tests/data/state_estimation/leaf-without-power-sensor/input.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/asym_output.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/input.json new file mode 100644 index 000000000..30e8d6ffc --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/input.json @@ -0,0 +1,27 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000} + ], + "line": [ + {"id": 2, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 3, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 4, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 6, "measured_object": 3, "measured_terminal_type": 2, "power_sigma": 17535.49694600984, "p_measured": 1503107.753161622, "q_measured": 903107.7531616191} + ], + "sym_voltage_sensor": [ + {"id": 5, "measured_object": 0, "u_sigma": 10, "u_measured": 9947.061877982074} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/middle-without-power-sensor/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/input.json.license similarity index 100% rename from tests/data/state_estimation/middle-without-power-sensor/input.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/input.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/leaf-without-power-sensor/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/params.json.license similarity index 100% rename from tests/data/state_estimation/leaf-without-power-sensor/params.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/params.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/sym_output.json new file mode 100644 index 000000000..38fbf5533 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/sym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9947061877982075, "u": 9947.061877982074, "u_angle": -0.007066394337767276, "p": 1503107.753161622, "q": 903107.7531616191}, + {"id": 1, "energized": 1, "u_pu": 0.9922873497821686, "u": 9922.873497821685, "u_angle": -0.007674275944600428, "p": -1500000.000000038, "q": -900000.0000000356} + ], + "line": [ + {"id": 2, "energized": 1, "p_from": 1503107.753161622, "q_from": 903107.7531616191, "i_from": 101.7800432564162, "s_from": 1753549.694600984, "p_to": -1500000.000000038, "q_to": -900000.0000000356, "i_to": 101.7800432564162, "s_to": 1749285.568453641} + ], + "source": [ + {"id": 3, "energized": 1, "p": 1503107.753161622, "q": 903107.7531616191, "i": 101.7800432564162, "s": 1753549.694600984, "pf": 0.8571800147948756} + ], + "sym_load": [ + {"id": 4, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7800432564132, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/leaf-without-power-sensor/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/sym_output.json.license similarity index 100% rename from tests/data/state_estimation/leaf-without-power-sensor/sym_output.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-no-capacitance/sym_output.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/asym_output.json new file mode 100644 index 000000000..f357f73c7 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/asym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9948621102685431, 0.9948621102685432, 0.9948621102685431], "u": [5743.839071701025, 5743.839071701026, 5743.839071701025], "u_angle": [-0.007081445077385682, -2.10147654747058, 2.08731365731581], "p": [501077.9919926791, 501077.9919926159, 501077.9919926883], "q": [290686.6533223243, 290686.6533222981, 290686.6533222449]}, + {"id": 1, "energized": 1, "u_pu": [0.9924591930531835, 0.9924591930531839, 0.9924591930531835], "u": [5729.965822689743, 5729.965822689745, 5729.965822689743], "u_angle": [-0.007704874551230438, -2.102099976944424, 2.086690227841965], "p": [-500000.0000000487, -499999.999999976, -500000.0000000432], "q": [-299999.9999999708, -299999.9999999429, -299999.9999999404]} + ], + "line": [ + {"id": 2, "energized": 1, "p_from": [501077.9919926791, 501077.9919926159, 501077.9919926883], "q_from": [290686.6533223243, 290686.6533222981, 290686.6533222449], "i_from": [100.8542960480469, 100.8542960480351, 100.8542960480414], "s_from": [579290.846189674, 579290.8461896062, 579290.8461896421], "p_to": [-500000.0000000487, -499999.999999976, -500000.0000000432], "q_to": [-299999.9999999708, -299999.9999999429, -299999.9999999404], "i_to": [101.7624201484054, 101.762420148392, 101.7624201484018], "s_to": [583095.1894845568, 583095.1894844801, 583095.1894845364]} + ], + "source": [ + {"id": 3, "energized": 1, "p": [501077.991992679, 501077.9919926159, 501077.9919926884], "q": [290686.6533223243, 290686.653322298, 290686.6533222449], "i": [100.8542960480469, 100.8542960480351, 100.8542960480414], "s": [579290.846189674, 579290.8461896061, 579290.8461896422], "pf": [0.8649851715913596, 0.8649851715913518, 0.8649851715914232]} + ], + "sym_load": [ + {"id": 4, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7624201484007, 101.7624201484007, 101.7624201484007], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/middle-without-power-sensor/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/asym_output.json.license similarity index 100% rename from tests/data/state_estimation/middle-without-power-sensor/params.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/asym_output.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/input.json new file mode 100644 index 000000000..c83c5b1a3 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/input.json @@ -0,0 +1,27 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000} + ], + "line": [ + {"id": 2, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 3, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 4, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 6, "measured_object": 3, "measured_terminal_type": 2, "power_sigma": 17378.72538568819, "p_measured": 1503233.975977867, "q_measured": 872059.9599668625} + ], + "sym_voltage_sensor": [ + {"id": 5, "measured_object": 0, "u_sigma": 10, "u_measured": 9948.621102685433} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/middle-without-power-sensor/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/input.json.license similarity index 100% rename from tests/data/state_estimation/middle-without-power-sensor/sym_output.json.license rename to tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/input.json.license diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json new file mode 100644 index 000000000..441d0d5c9 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9948621102685433, "u": 9948.621102685433, "u_angle": -0.007081445077384819, "p": 1503233.975977867, "q": 872059.9599668625}, + {"id": 1, "energized": 1, "u_pu": 0.9924591930531839, "u": 9924.591930531838, "u_angle": -0.007704874551229372, "p": -1499999.999999921, "q": -899999.9999999725} + ], + "line": [ + {"id": 2, "energized": 1, "p_from": 1503233.975977867, "q_from": 872059.9599668625, "i_from": 100.8542960480351, "s_from": 1737872.538568819, "p_to": -1499999.999999921, "q_to": -899999.9999999725, "i_to": 101.7624201483959, "s_to": 1749285.568453508} + ], + "source": [ + {"id": 3, "energized": 1, "p": 1503233.975977867, "q": 872059.9599668625, "i": 100.8542960480351, "s": 1737872.538568819, "pf": 0.8649851715913627} + ], + "sym_load": [ + {"id": 4, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7624201484007, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid0-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json new file mode 100644 index 000000000..b04a08baf --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9947061877982084, 0.9947061877982086, 0.9947061877982075], "u": [5742.93885289882, 5742.938852898822, 5742.938852898816], "u_angle": [-0.007066394337767047, -2.101461496730962, 2.087328708055428], "p": [501035.9177205032, 501035.9177204924, 501035.9177205171], "q": [301035.9177205591, 301035.9177205543, 301035.9177205773]}, + {"id": 1, "energized": 1, "u_pu": [0.9922873497821693, 0.9922873497821699, 0.9922873497821685], "u": [5728.973685101958, 5728.973685101962, 5728.973685101953], "u_angle": [-0.007674275944600129, -2.102069378337795, 2.086720826448595], "p": [-499999.9999999756, -499999.9999999649, -499999.9999999893], "q": [-300000.0000000313, -300000.0000000268, -300000.0000000495]}, + {"id": 2, "energized": 1, "u_pu": [0.9922873497821693, 0.9922873497821699, 0.9922873497821685], "u": [5728.973685101958, 5728.973685101962, 5728.973685101953], "u_angle": [-0.007674275944600113, -2.102069378337795, 2.086720826448595], "p": [0, -0, 0], "q": [-0, 0, 0]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501035.9177205032, 501035.9177204924, 501035.9177205171], "q_from": [301035.9177205591, 301035.9177205543, 301035.9177205773], "i_from": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s_from": [584516.5648669729, 584516.5648669612, 584516.5648669942], "p_to": [-499999.9999999756, -499999.9999999649, -499999.9999999893], "q_to": [-300000.0000000313, -300000.0000000268, -300000.0000000495], "i_to": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s_to": [583095.1894845252, 583095.1894845137, 583095.1894845464]}, + {"id": 4, "energized": 1, "p_from": [0, -0, 0], "q_from": [-0, 0, 0], "i_from": [0, 0, 0], "s_from": [0, 0, 0], "p_to": [0, -0, 0], "q_to": [-0, 0, 0], "i_to": [0, 0, 0], "s_to": [0, 0, 0]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [501035.9177205033, 501035.9177204923, 501035.9177205171], "q": [301035.9177205591, 301035.9177205543, 301035.9177205774], "i": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s": [584516.564866973, 584516.5648669611, 584516.5648669943], "pf": [0.857180014794844, 0.8571800147948427, 0.8571800147948365]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7800432564132, 101.7800432564131, 101.7800432564133], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json new file mode 100644 index 000000000..bd6faed39 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json @@ -0,0 +1,30 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17535.49694600984, "p_measured": 1503107.753161622, "q_measured": 903107.7531616191}, + {"id": 9, "measured_object": 4, "measured_terminal_type": 0, "power_sigma": 17535.49694600984, "p_measured": 0, "q_measured": -0} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9947.061877982074} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json new file mode 100644 index 000000000..2100485a5 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9947061877982075, "u": 9947.061877982074, "u_angle": -0.007066394337767276, "p": 1503107.753161622, "q": 903107.7531616191}, + {"id": 1, "energized": 1, "u_pu": 0.9922873497821686, "u": 9922.873497821685, "u_angle": -0.007674275944600428, "p": -1500000.000000038, "q": -900000.0000000356}, + {"id": 2, "energized": 1, "u_pu": 0.9922873497821685, "u": 9922.873497821685, "u_angle": -0.007674275944600375, "p": 0, "q": -0} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503107.753161622, "q_from": 903107.7531616191, "i_from": 101.7800432564162, "s_from": 1753549.694600984, "p_to": -1500000.000000038, "q_to": -900000.0000000356, "i_to": 101.7800432564162, "s_to": 1749285.568453641}, + {"id": 4, "energized": 1, "p_from": 0, "q_from": -0, "i_from": 0, "s_from": 0, "p_to": 0, "q_to": -0, "i_to": 0, "s_to": 0} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1503107.753161622, "q": 903107.7531616191, "i": 101.7800432564162, "s": 1753549.694600984, "pf": 0.8571800147948756} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7800432564132, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-no-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json new file mode 100644 index 000000000..133ba2dcb --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.995017867285788, 0.9950178672857882, 0.995017867285788], "u": [5744.738335259371, 5744.738335259372, 5744.738335259371], "u_angle": [-0.007096347049360697, -2.101491449442555, 2.087298755343836], "p": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q": [280346.0409314471, 280346.0409315173, 280346.0409315187]}, + {"id": 1, "energized": 1, "u_pu": [0.9926464181559117, 0.9926464181559123, 0.9926464181559118], "u": [5731.046767324335, 5731.046767324337, 5731.046767324335], "u_angle": [-0.00775106556205689, -2.10214616795525, 2.08664403683114], "p": [-500000.0000000445, -499999.9999998914, -499999.9999999729], "q": [-299999.9999999827, -300000.0000000969, -300000.0000000309]}, + {"id": 2, "energized": 1, "u_pu": [0.9926619327659089, 0.9926619327659096, 0.9926619327659091], "u": [5731.136340966917, 5731.136340966921, 5731.136340966918], "u_angle": [-0.007766852311877682, -2.102161954705072, 2.086628250081319], "p": [3.761639740672792e-08, 5.691772969808456e-09, 3.272283919211628e-08], "q": [-2.921668780776623e-10, 8.392256727000096e-08, 1.855517476480437e-08]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q_from": [280346.0409314471, 280346.0409315173, 280346.0409315187], "i_from": [99.95244643179761, 99.95244643178407, 99.95244643178361], "s_from": [574200.6507197062, 574200.6507196287, 574200.6507196259], "p_to": [-500051.6744961346, -500051.6744959863, -500051.6744960202], "q_to": [-289681.3910431248, -289681.3910431431, -289681.3910431646], "i_to": [100.8365122405332, 100.8365122405123, 100.8365122405194], "s_to": [577898.7675043683, 577898.7675042492, 577898.7675042893]}, + {"id": 4, "energized": 1, "p_from": [51.67449609008805, 51.67449609480625, 51.67449604720775], "q_from": [-10318.6089568579, -10318.60895695369, -10318.60895686631], "i_from": [1.800498018105367, 1.800498018122083, 1.800498018106796], "s_from": [10318.73834623663, 10318.73834633244, 10318.73834624482], "p_to": [3.761639740672792e-08, 5.691772969808456e-09, 3.272283919211628e-08], "q_to": [-2.921668780776623e-10, 8.392256727000096e-08, 1.855517476480437e-08], "i_to": [6.563712636189232e-12, 1.467690763929347e-11, 6.563712636189232e-12], "s_to": [3.761753202092786e-08, 8.411535874456982e-08, 3.761753202092787e-08]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q": [280346.0409314471, 280346.0409315172, 280346.0409315187], "i": [99.95244643179761, 99.95244643178405, 99.95244643178361], "s": [574200.6507197062, 574200.6507196286, 574200.6507196259], "pf": [0.8727110446790789, 0.8727110446789736, 0.8727110446789709]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7432265269685, 101.7432265269684, 101.7432265269685], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json new file mode 100644 index 000000000..0fd429505 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json @@ -0,0 +1,30 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17226.01952159174, "p_measured": 1503333.749235006, "q_measured": 841038.1227944542}, + {"id": 9, "measured_object": 4, "measured_terminal_type": 0, "power_sigma": 17226.01952159174, "p_measured": 155.0234884395419, "q_measured": -30955.826870575} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9950.178672857875} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json new file mode 100644 index 000000000..17fc55134 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9950178672857876, "u": 9950.178672857875, "u_angle": -0.007096347049360632, "p": 1503333.749235005, "q": 841038.1227944541}, + {"id": 1, "energized": 1, "u_pu": 0.9926464181559111, "u": 9926.464181559111, "u_angle": -0.007751065562056674, "p": -1499999.999999963, "q": -899999.9999999491}, + {"id": 2, "energized": 1, "u_pu": 0.9926619327659083, "u": 9926.619327659084, "u_angle": -0.007766852311877548, "p": 5.642459611009186e-08, "q": -4.382503171164858e-10} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503333.749235005, "q_from": 841038.1227944541, "i_from": 99.95244643180085, "s_from": 1722601.952159174, "p_to": -1500155.023488403, "q_to": -869044.1731293742, "i_to": 100.8365122405332, "s_to": 1733696.302513104}, + {"id": 4, "energized": 1, "p_from": 155.0234884395419, "q_from": -30955.826870575, "i_from": 1.800498018105492, "s_from": 30956.21503871204, "p_to": 5.642459611009186e-08, "q_to": -4.382503171164858e-10, "i_to": 3.281856318094616e-12, "s_to": 5.642629803139177e-08} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1503333.749235006, "q": 841038.1227944542, "i": 99.95244643180087, "s": 1722601.952159174, "pf": 0.8727110446790509} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7432265269685, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid1-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json new file mode 100644 index 000000000..b04a08baf --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9947061877982084, 0.9947061877982086, 0.9947061877982075], "u": [5742.93885289882, 5742.938852898822, 5742.938852898816], "u_angle": [-0.007066394337767047, -2.101461496730962, 2.087328708055428], "p": [501035.9177205032, 501035.9177204924, 501035.9177205171], "q": [301035.9177205591, 301035.9177205543, 301035.9177205773]}, + {"id": 1, "energized": 1, "u_pu": [0.9922873497821693, 0.9922873497821699, 0.9922873497821685], "u": [5728.973685101958, 5728.973685101962, 5728.973685101953], "u_angle": [-0.007674275944600129, -2.102069378337795, 2.086720826448595], "p": [-499999.9999999756, -499999.9999999649, -499999.9999999893], "q": [-300000.0000000313, -300000.0000000268, -300000.0000000495]}, + {"id": 2, "energized": 1, "u_pu": [0.9922873497821693, 0.9922873497821699, 0.9922873497821685], "u": [5728.973685101958, 5728.973685101962, 5728.973685101953], "u_angle": [-0.007674275944600113, -2.102069378337795, 2.086720826448595], "p": [0, -0, 0], "q": [-0, 0, 0]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501035.9177205032, 501035.9177204924, 501035.9177205171], "q_from": [301035.9177205591, 301035.9177205543, 301035.9177205773], "i_from": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s_from": [584516.5648669729, 584516.5648669612, 584516.5648669942], "p_to": [-499999.9999999756, -499999.9999999649, -499999.9999999893], "q_to": [-300000.0000000313, -300000.0000000268, -300000.0000000495], "i_to": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s_to": [583095.1894845252, 583095.1894845137, 583095.1894845464]}, + {"id": 4, "energized": 1, "p_from": [0, -0, 0], "q_from": [-0, 0, 0], "i_from": [0, 0, 0], "s_from": [0, 0, 0], "p_to": [0, -0, 0], "q_to": [-0, 0, 0], "i_to": [0, 0, 0], "s_to": [0, 0, 0]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [501035.9177205033, 501035.9177204923, 501035.9177205171], "q": [301035.9177205591, 301035.9177205543, 301035.9177205774], "i": [101.7800432564123, 101.7800432564103, 101.7800432564161], "s": [584516.564866973, 584516.5648669611, 584516.5648669943], "pf": [0.857180014794844, 0.8571800147948427, 0.8571800147948365]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7800432564132, 101.7800432564131, 101.7800432564133], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json new file mode 100644 index 000000000..976c27540 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json @@ -0,0 +1,29 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17535.49694600984, "p_measured": 1503107.753161622, "q_measured": 903107.7531616191} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9947.061877982074} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json new file mode 100644 index 000000000..2100485a5 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9947061877982075, "u": 9947.061877982074, "u_angle": -0.007066394337767276, "p": 1503107.753161622, "q": 903107.7531616191}, + {"id": 1, "energized": 1, "u_pu": 0.9922873497821686, "u": 9922.873497821685, "u_angle": -0.007674275944600428, "p": -1500000.000000038, "q": -900000.0000000356}, + {"id": 2, "energized": 1, "u_pu": 0.9922873497821685, "u": 9922.873497821685, "u_angle": -0.007674275944600375, "p": 0, "q": -0} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503107.753161622, "q_from": 903107.7531616191, "i_from": 101.7800432564162, "s_from": 1753549.694600984, "p_to": -1500000.000000038, "q_to": -900000.0000000356, "i_to": 101.7800432564162, "s_to": 1749285.568453641}, + {"id": 4, "energized": 1, "p_from": 0, "q_from": -0, "i_from": 0, "s_from": 0, "p_to": 0, "q_to": -0, "i_to": 0, "s_to": 0} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1503107.753161622, "q": 903107.7531616191, "i": 101.7800432564162, "s": 1753549.694600984, "pf": 0.8571800147948756} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7800432564132, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-no-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json new file mode 100644 index 000000000..133ba2dcb --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.995017867285788, 0.9950178672857882, 0.995017867285788], "u": [5744.738335259371, 5744.738335259372, 5744.738335259371], "u_angle": [-0.007096347049360697, -2.101491449442555, 2.087298755343836], "p": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q": [280346.0409314471, 280346.0409315173, 280346.0409315187]}, + {"id": 1, "energized": 1, "u_pu": [0.9926464181559117, 0.9926464181559123, 0.9926464181559118], "u": [5731.046767324335, 5731.046767324337, 5731.046767324335], "u_angle": [-0.00775106556205689, -2.10214616795525, 2.08664403683114], "p": [-500000.0000000445, -499999.9999998914, -499999.9999999729], "q": [-299999.9999999827, -300000.0000000969, -300000.0000000309]}, + {"id": 2, "energized": 1, "u_pu": [0.9926619327659089, 0.9926619327659096, 0.9926619327659091], "u": [5731.136340966917, 5731.136340966921, 5731.136340966918], "u_angle": [-0.007766852311877682, -2.102161954705072, 2.086628250081319], "p": [3.761639740672792e-08, 5.691772969808456e-09, 3.272283919211628e-08], "q": [-2.921668780776623e-10, 8.392256727000096e-08, 1.855517476480437e-08]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q_from": [280346.0409314471, 280346.0409315173, 280346.0409315187], "i_from": [99.95244643179761, 99.95244643178407, 99.95244643178361], "s_from": [574200.6507197062, 574200.6507196287, 574200.6507196259], "p_to": [-500051.6744961346, -500051.6744959863, -500051.6744960202], "q_to": [-289681.3910431248, -289681.3910431431, -289681.3910431646], "i_to": [100.8365122405332, 100.8365122405123, 100.8365122405194], "s_to": [577898.7675043683, 577898.7675042492, 577898.7675042893]}, + {"id": 4, "energized": 1, "p_from": [51.67449609008805, 51.67449609480625, 51.67449604720775], "q_from": [-10318.6089568579, -10318.60895695369, -10318.60895686631], "i_from": [1.800498018105367, 1.800498018122083, 1.800498018106796], "s_from": [10318.73834623663, 10318.73834633244, 10318.73834624482], "p_to": [3.761639740672792e-08, 5.691772969808456e-09, 3.272283919211628e-08], "q_to": [-2.921668780776623e-10, 8.392256727000096e-08, 1.855517476480437e-08], "i_to": [6.563712636189232e-12, 1.467690763929347e-11, 6.563712636189232e-12], "s_to": [3.761753202092786e-08, 8.411535874456982e-08, 3.761753202092787e-08]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [501111.2497450017, 501111.2497448735, 501111.2497448696], "q": [280346.0409314471, 280346.0409315172, 280346.0409315187], "i": [99.95244643179761, 99.95244643178405, 99.95244643178361], "s": [574200.6507197062, 574200.6507196286, 574200.6507196259], "pf": [0.8727110446790789, 0.8727110446789736, 0.8727110446789709]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.7432265269685, 101.7432265269684, 101.7432265269685], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json new file mode 100644 index 000000000..e7374c3dc --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json @@ -0,0 +1,29 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17226.01952159174, "p_measured": 1503333.749235006, "q_measured": 841038.1227944542} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9950.178672857875} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json new file mode 100644 index 000000000..17fc55134 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9950178672857876, "u": 9950.178672857875, "u_angle": -0.007096347049360632, "p": 1503333.749235005, "q": 841038.1227944541}, + {"id": 1, "energized": 1, "u_pu": 0.9926464181559111, "u": 9926.464181559111, "u_angle": -0.007751065562056674, "p": -1499999.999999963, "q": -899999.9999999491}, + {"id": 2, "energized": 1, "u_pu": 0.9926619327659083, "u": 9926.619327659084, "u_angle": -0.007766852311877548, "p": 5.642459611009186e-08, "q": -4.382503171164858e-10} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503333.749235005, "q_from": 841038.1227944541, "i_from": 99.95244643180085, "s_from": 1722601.952159174, "p_to": -1500155.023488403, "q_to": -869044.1731293742, "i_to": 100.8365122405332, "s_to": 1733696.302513104}, + {"id": 4, "energized": 1, "p_from": 155.0234884395419, "q_from": -30955.826870575, "i_from": 1.800498018105492, "s_from": 30956.21503871204, "p_to": 5.642459611009186e-08, "q_to": -4.382503171164858e-10, "i_to": 3.281856318094616e-12, "s_to": 5.642629803139177e-08} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1503333.749235006, "q": 841038.1227944542, "i": 99.95244643180087, "s": 1722601.952159174, "pf": 0.8727110446790509} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.7432265269685, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid2-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json new file mode 100644 index 000000000..b660460e0 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9946887264570634, 0.9946887264570632, 0.9946887264570634], "u": [5742.838039798716, 5742.838039798715, 5742.838039798716], "u_angle": [-0.007080647130854444, -2.101475749524051, 2.087314455262341], "p": [502082.0986237937, 502082.0986239082, 502082.0986238733], "q": [302082.0986238646, 302082.0986238178, 302082.0986238002]}, + {"id": 1, "energized": 1, "u_pu": [0.9922635353842043, 0.9922635353842039, 0.9922635353842042], "u": [5728.836192611201, 5728.836192611198, 5728.8361926112], "u_angle": [-0.007688553998255267, -2.102083656391452, 2.08670654839494], "p": [7.505809345210201e-08, -8.346973750260934e-08, -7.908397587951802e-08], "q": [-1.93788725501103e-08, 1.362796750093407e-07, 6.322034558489565e-08]}, + {"id": 2, "energized": 1, "u_pu": [0.9898387127998624, 0.989838712799862, 0.9898387127998626], "u": [5714.836472893132, 5714.83647289313, 5714.836472893133], "u_angle": [-0.008299439489281382, -2.102694541882478, 2.086095662903914], "p": [-500000.0000000193, -499999.9999999751, -499999.9999999448], "q": [-299999.9999999958, -300000.0000001043, -300000.000000014]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [502082.0986237937, 502082.0986239082, 502082.0986238733], "q_from": [302082.0986238646, 302082.0986238178, 302082.0986238002], "i_from": [102.0318240513536, 102.0318240513665, 102.0318240513597], "s_from": [585952.2404321629, 585952.2404322368, 585952.2404321978], "p_to": [-501041.0493118691, -501041.0493119833, -501041.0493119486], "q_to": [-301041.04931194, -301041.0493118929, -301041.0493118754], "i_to": [102.0318240513536, 102.0318240513665, 102.0318240513597], "s_to": [584523.6064235325, 584523.6064236062, 584523.6064235674]}, + {"id": 4, "energized": 1, "p_from": [501041.0493119441, 501041.0493118999, 501041.0493118694], "q_from": [301041.0493119206, 301041.0493120292, 301041.0493119386], "i_from": [102.0318240513631, 102.0318240513663, 102.0318240513536], "s_from": [584523.6064235868, 584523.6064236049, 584523.6064235321], "p_to": [-500000.0000000193, -499999.9999999751, -499999.9999999448], "q_to": [-299999.9999999958, -300000.0000001043, -300000.000000014], "i_to": [102.0318240513631, 102.0318240513663, 102.0318240513536], "s_to": [583095.1894845444, 583095.1894845624, 583095.18948449]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [502082.0986237937, 502082.0986239082, 502082.0986238733], "q": [302082.0986238646, 302082.0986238177, 302082.0986238002], "i": [102.0318240513536, 102.0318240513665, 102.0318240513597], "s": [585952.2404321628, 585952.2404322368, 585952.2404321978], "pf": [0.8568652254891771, 0.8568652254892644, 0.8568652254892618]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [102.0318240513606, 102.0318240513606, 102.0318240513605], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json new file mode 100644 index 000000000..82ef76bb1 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json @@ -0,0 +1,30 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17578.56721296711, "p_measured": 2711243.332568895, "q_measured": 1631243.332568967}, + {"id": 9, "measured_object": 3, "measured_terminal_type": 0, "power_sigma": 8789.283606483557, "p_measured": 1204997.036697287, "q_measured": 724997.0366973188} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9946.887264570634} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json new file mode 100644 index 000000000..9318dd423 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9946887264570634, "u": 9946.887264570634, "u_angle": -0.007080647130854704, "p": 1506246.295871608, "q": 906246.2958716485}, + {"id": 1, "energized": 1, "u_pu": 0.9922635353842041, "u": 9922.635353842041, "u_angle": -0.007688553998255594, "p": -8.673164994138707e-10, "q": -1.128039693030065e-07}, + {"id": 2, "energized": 1, "u_pu": 0.9898387127998622, "u": 9898.387127998622, "u_angle": -0.008299439489281751, "p": -1500000.000000058, "q": -899999.9999999867} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1506246.295871608, "q_from": 906246.2958716485, "i_from": 102.0318240513665, "s_from": 1757856.721296711, "p_to": -1503123.147935833, "q_to": -903123.1479358739, "i_to": 102.0318240513665, "s_to": 1753570.819270819}, + {"id": 4, "energized": 1, "p_from": 1503123.147935832, "q_from": 903123.1479357611, "i_from": 102.0318240513631, "s_from": 1753570.819270761, "p_to": -1500000.000000058, "q_to": -899999.9999999867, "i_to": 102.0318240513631, "s_to": 1749285.568453633} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1506246.295871608, "q": 906246.2958716485, "i": 102.0318240513665, "s": 1757856.721296711, "pf": 0.8568652254891976} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 102.0318240513606, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-no-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json new file mode 100644 index 000000000..4dd7cee93 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9950001943413628, 0.9950001943413634, 0.9950001943413617], "u": [5744.636300467158, 5744.636300467161, 5744.636300467151], "u_angle": [-0.007110418039268042, -2.101505520432464, 2.087284684353926], "p": [502147.0585833219, 502147.0585833269, 502147.0585833932], "q": [281408.0800057805, 281408.0800058427, 281408.0800058083]}, + {"id": 1, "energized": 1, "u_pu": [0.9926223784320097, 0.9926223784320103, 0.9926223784320078], "u": [5730.907973913674, 5730.907973913677, 5730.907973913663], "u_angle": [-0.007765084925625658, -2.102160187318821, 2.086630017467568], "p": [1.895349389432269e-08, 1.053955946708715e-07, -9.791336816028413e-08], "q": [1.866140513819525e-08, -6.194631884748168e-08, 2.015364291018367e-08]}, + {"id": 2, "energized": 1, "u_pu": [0.990213941647649, 0.9902139416476498, 0.9902139416476472], "u": [5717.002857655905, 5717.00285765591, 5717.002857655895], "u_angle": [-0.008391266374491493, -2.102786368767687, 2.086003836018703], "p": [-500000.0000000018, -500000.0000000434, -500000.0000000083], "q": [-300000.0000000299, -299999.9999999707, -300000.0000000731]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [502147.0585833219, 502147.0585833269, 502147.0585833932], "q_from": [281408.0800057805, 281408.0800058427, 281408.0800058083], "i_from": [100.201868894777, 100.201868894783, 100.2018688947903], "s_from": [575623.293427587, 575623.2934276218, 575623.2934276627], "p_to": [-501082.4600070894, -501082.4600070579, -501082.4600071934], "q_to": [-290737.9705837811, -290737.9705837948, -290737.9705838122], "i_to": [101.0870294891334, 101.0870294891298, 101.087029489152], "s_to": [579320.4633585213, 579320.4633585011, 579320.4633586269]}, + {"id": 4, "energized": 1, "p_from": [501082.4600071083, 501082.4600071633, 501082.4600070955], "q_from": [290737.9705837998, 290737.9705837329, 290737.9705838324], "i_from": [101.0870294891379, 101.0870294891403, 101.087029489139], "s_from": [579320.4633585471, 579320.463358561, 579320.4633585524], "p_to": [-500000.0000000018, -500000.0000000434, -500000.0000000083], "q_to": [-300000.0000000299, -299999.9999999707, -300000.0000000731], "i_to": [101.9931604028669, 101.9931604028677, 101.9931604028719], "s_to": [583095.189484547, 583095.1894845521, 583095.1894845748]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [502147.0585833219, 502147.0585833269, 502147.0585833932], "q": [281408.0800057805, 281408.0800058428, 281408.0800058083], "i": [100.201868894777, 100.201868894783, 100.2018688947903], "s": [575623.293427587, 575623.2934276218, 575623.2934276627], "pf": [0.872353610975772, 0.8723536109757279, 0.8723536109757811]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [101.9931604028639, 101.9931604028638, 101.9931604028641], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json new file mode 100644 index 000000000..472bf2b06 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json @@ -0,0 +1,30 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 8, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 17268.69880282992, "p_measured": 2711594.116350247, "q_measured": 1519603.632031518}, + {"id": 9, "measured_object": 3, "measured_terminal_type": 0, "power_sigma": 8634.349401414962, "p_measured": 1205152.94060011, "q_measured": 675379.392014008} + ], + "sym_voltage_sensor": [ + {"id": 7, "measured_object": 0, "u_sigma": 10, "u_measured": 9950.001943413628} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json new file mode 100644 index 000000000..bca9f46fe --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json @@ -0,0 +1,23 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9950001943413628, "u": 9950.001943413628, "u_angle": -0.007110418039268063, "p": 1506441.175750137, "q": 844224.24001751}, + {"id": 1, "energized": 1, "u_pu": 0.9926223784320094, "u": 9926.223784320095, "u_angle": -0.007765084925625582, "p": -8.762662683823032e-10, "q": -1.128446970975538e-07}, + {"id": 2, "energized": 1, "u_pu": 0.9902139416476489, "u": 9902.139416476488, "u_angle": -0.00839126637449151, "p": -1499999.999999948, "q": -899999.9999999774} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1506441.175750137, "q_from": 844224.24001751, "i_from": 100.2018688947905, "s_from": 1726869.880282992, "p_to": -1503247.380021381, "q_to": -872213.9117514552, "i_to": 101.0870294891424, "s_to": 1737961.390075718}, + {"id": 4, "energized": 1, "p_from": 1503247.38002138, "q_from": 872213.9117513422, "i_from": 101.0870294891391, "s_from": 1737961.390075661, "p_to": -1499999.999999948, "q_to": -899999.9999999774, "i_to": 101.9931604028607, "s_to": 1749285.568453534} + ], + "source": [ + {"id": 5, "energized": 1, "p": 1506441.175750137, "q": 844224.24001751, "i": 100.2018688947905, "s": 1726869.880282992, "pf": 0.8723536109757541} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 101.9931604028639, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid3-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json new file mode 100644 index 000000000..aa63e539a --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json @@ -0,0 +1,25 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9837501416891404, 0.9837501416891397, 0.9837501416891389], "u": [5679.684091195577, 5679.684091195572, 5679.684091195568], "u_angle": [-0.02146692284126047, -2.115862025234457, 2.072928179551933], "p": [1505317.491973749, 1505317.49197392, 1505317.491973825], "q": [905317.4919738546, 905317.4919738603, 905317.4919738517]}, + {"id": 1, "energized": 1, "u_pu": [0.9813042269632496, 0.9813042269632485, 0.9813042269632478], "u": [5665.562595941497, 5665.562595941491, 5665.562595941487], "u_angle": [-0.02208845384999588, -2.116483556243193, 2.072306648543198], "p": [-499999.9999999412, -500000.0000000325, -499999.9999999489], "q": [-299999.9999999705, -299999.999999998, -299999.9999999704]}, + {"id": 2, "energized": 1, "u_pu": [0.9788456424477889, 0.9788456424477879, 0.978845642447787], "u": [5651.367951623231, 5651.367951623225, 5651.367951623221], "u_angle": [-0.02271310732266705, -2.117108209715864, 2.071681995070526], "p": [-999999.9999999588, -1000000.000000018, -1000000.000000012], "q": [-600000.0000000151, -599999.999999993, -600000.000000004]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501059.2362438705, 501059.2362439621, 501059.2362438784], "q_from": [301059.2362438999, 301059.2362439276, 301059.2362438999], "i_from": [102.9192034524801, 102.9192034524966, 102.9192034524815], "s_from": [584548.5625275724, 584548.5625276652, 584548.562527579], "p_to": [-499999.9999999412, -500000.0000000325, -499999.9999999489], "q_to": [-299999.9999999705, -299999.999999998, -299999.9999999704], "i_to": [102.9192034524801, 102.9192034524966, 102.9192034524815], "s_to": [583095.1894844645, 583095.1894845569, 583095.189484471]}, + {"id": 4, "energized": 1, "p_from": [1004258.255729898, 1004258.255729958, 1004258.255729951], "q_from": [604258.2557299545, 604258.2557299327, 604258.2557299436], "i_from": [206.3554149989597, 206.3554149989669, 206.3554149989671], "s_from": [1172033.567701652, 1172033.567701693, 1172033.567701693], "p_to": [-999999.9999999588, -1000000.000000018, -1000000.000000012], "q_to": [-600000.0000000151, -599999.999999993, -600000.000000004], "i_to": [206.3554149989597, 206.3554149989669, 206.3554149989671], "s_to": [1166190.378969033, 1166190.378969072, 1166190.378969072]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [1505317.491973749, 1505317.49197392, 1505317.491973825], "q": [905317.4919738545, 905317.4919738603, 905317.4919738518], "i": [309.2746050541666, 309.2746050541931, 309.2746050541783], "s": [1756582.054136945, 1756582.054137094, 1756582.054137009], "pf": [0.8569582550547867, 0.8569582550548113, 0.8569582550547991]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [102.9192034524917, 102.9192034524918, 102.9192034524919], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 7, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [103.1777074994823, 103.1777074994824, 103.1777074994825], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 8, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [103.1777074994823, 103.1777074994824, 103.1777074994825], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json new file mode 100644 index 000000000..081d16282 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json @@ -0,0 +1,34 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 4, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 7, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 8, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 10, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 52697.46162410962, "p_measured": 4515952.475921471, "q_measured": 2715952.475921441}, + {"id": 11, "measured_object": 4, "measured_terminal_type": 1, "power_sigma": 52697.46162410962, "p_measured": -5399999.999999974, "q_measured": -3239999.999999869}, + {"id": 12, "measured_object": 7, "measured_terminal_type": 4, "power_sigma": 18631.36623286288, "p_measured": 1199999.999999994, "q_measured": 719999.9999999709}, + {"id": 13, "measured_object": 8, "measured_terminal_type": 4, "power_sigma": 18631.36623286288, "p_measured": 1199999.999999994, "q_measured": 719999.9999999709} + ], + "sym_voltage_sensor": [ + {"id": 9, "measured_object": 0, "u_sigma": 10, "u_measured": 9837.5014168914} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json new file mode 100644 index 000000000..35d13fb12 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json @@ -0,0 +1,25 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9837501416891401, "u": 9837.5014168914, "u_angle": -0.02146692284126162, "p": 4515952.475921472, "q": 2715952.475921441}, + {"id": 1, "energized": 1, "u_pu": 0.9813042269632491, "u": 9813.042269632491, "u_angle": -0.02208845384999703, "p": -1499999.99999988, "q": -899999.9999999083}, + {"id": 2, "energized": 1, "u_pu": 0.9788456424477885, "u": 9788.456424477885, "u_angle": -0.02271310732266829, "p": -2999999.999999986, "q": -1799999.999999927} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503177.708731668, "q_from": 903177.7087316965, "i_from": 102.9192034524829, "s_from": 1753645.687582764, "p_to": -1499999.99999988, "q_to": -899999.9999999083, "i_to": 102.9192034524829, "s_to": 1749285.56845344}, + {"id": 4, "energized": 1, "p_from": 3012774.767189804, "q_from": 1812774.767189745, "i_from": 206.3554149989617, "s_from": 3516100.703104991, "p_to": -2999999.999999986, "q_to": -1799999.999999927, "i_to": 206.3554149989617, "s_to": 3498571.13690713} + ], + "source": [ + {"id": 5, "energized": 1, "p": 4515952.475921471, "q": 2715952.475921441, "i": 309.2746050541742, "s": 5269746.162410962, "pf": 0.8569582550548083} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 102.9192034524917, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 7, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 103.1777074994823, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 8, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 103.1777074994823, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-no-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json new file mode 100644 index 000000000..2d2e1be5c --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json @@ -0,0 +1,25 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9840615222412396, 0.9840615222412417, 0.984061522241241], "u": [5681.481847651326, 5681.481847651337, 5681.481847651334], "u_angle": [-0.02149188729550814, -2.115886989688703, 2.072903215097687], "p": [1505387.081561065, 1505387.081561023, 1505387.081560875], "q": [885079.6571233894, 885079.6571232867, 885079.6571233479]}, + {"id": 1, "energized": 1, "u_pu": [0.9816317563290788, 0.9816317563290816, 0.9816317563290807], "u": [5667.453587616787, 5667.453587616804, 5667.453587616798], "u_angle": [-0.02212876185115423, -2.116523864244349, 2.072266340542042], "p": [-500000.0000000437, -499999.9999999935, -499999.9999999345], "q": [-300000.0000000345, -299999.9999999183, -299999.9999999998]}, + {"id": 2, "energized": 1, "u_pu": [0.9791739524933838, 0.9791739524933859, 0.9791739524933851], "u": [5653.26345055525, 5653.263450555261, 5653.263450555257], "u_angle": [-0.02275296785751509, -2.11714807025071, 2.071642134535681], "p": [-1000000, -1000000.000000001, -999999.9999999549], "q": [-600000.0000000094, -600000.0000000168, -600000.0000000111]} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": [501099.8415986365, 501099.8415985854, 501099.8415985358], "q_from": [290933.4494611169, 290933.4494609846, 290933.4494610818], "i_from": [101.9863546812542, 101.9863546812345, 101.9863546812357], "s_from": [579433.6228296757, 579433.6228295651, 579433.6228295709], "p_to": [-500000.0000000437, -499999.9999999935, -499999.9999999345], "q_to": [-300000.0000000345, -299999.9999999183, -299999.9999999998], "i_to": [102.8848636288139, 102.8848636287954, 102.8848636287941], "s_to": [583095.1894845853, 583095.1894844824, 583095.1894844738]}, + {"id": 4, "energized": 1, "p_from": [1004287.239962428, 1004287.239962418, 1004287.239962372], "q_from": [594146.2076622726, 594146.2076622703, 594146.207662284], "i_from": [205.3825580967798, 205.3825580967776, 205.382558096772], "s_from": [1166877.275651048, 1166877.275651038, 1166877.275651006], "p_to": [-1000000, -1000000.000000001, -999999.9999999549], "q_to": [-600000.0000000094, -600000.0000000168, -600000.0000000111], "i_to": [206.2862254994547, 206.286225499455, 206.2862254994477], "s_to": [1166190.378969065, 1166190.37896907, 1166190.378969027]} + ], + "source": [ + {"id": 5, "energized": 1, "p": [1505387.081561065, 1505387.081561023, 1505387.081560875], "q": [885079.6571233894, 885079.6571232866, 885079.657123348], "i": [307.3666203361285, 307.3666203361123, 307.3666203360957], "s": [1746297.874013651, 1746297.874013563, 1746297.874013467], "pf": [0.8620448458206719, 0.8620448458206914, 0.8620448458206544]} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [102.8848636288042, 102.8848636288039, 102.8848636288039], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 7, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [103.1431127497269, 103.1431127497266, 103.1431127497267], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 8, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [103.1431127497269, 103.1431127497266, 103.1431127497267], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json new file mode 100644 index 000000000..b2ac319b5 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json @@ -0,0 +1,34 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "line": [ + {"id": 3, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 4, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 5, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 6, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 7, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 8, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 10, "measured_object": 5, "measured_terminal_type": 2, "power_sigma": 52388.93622040714, "p_measured": 4516161.244682975, "q_measured": 2655238.971370068}, + {"id": 11, "measured_object": 4, "measured_terminal_type": 1, "power_sigma": 52388.93622040714, "p_measured": -5400000.000000008, "q_measured": -3239999.999999959}, + {"id": 12, "measured_object": 7, "measured_terminal_type": 4, "power_sigma": 18522.28603029971, "p_measured": 1200000.000000002, "q_measured": 719999.999999991}, + {"id": 13, "measured_object": 8, "measured_terminal_type": 4, "power_sigma": 18522.28603029971, "p_measured": 1200000.000000002, "q_measured": 719999.999999991} + ], + "sym_voltage_sensor": [ + {"id": 9, "measured_object": 0, "u_sigma": 10, "u_measured": 9840.615222412414} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json new file mode 100644 index 000000000..4ac329fea --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json @@ -0,0 +1,25 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9840615222412414, "u": 9840.615222412414, "u_angle": -0.02149188729550769, "p": 4516161.244682975, "q": 2655238.971370068}, + {"id": 1, "energized": 1, "u_pu": 0.9816317563290811, "u": 9816.317563290811, "u_angle": -0.02212876185115365, "p": -1499999.999999964, "q": -899999.9999999987}, + {"id": 2, "energized": 1, "u_pu": 0.9791739524933857, "u": 9791.739524933857, "u_angle": -0.02275296785751467, "p": -3000000.000000005, "q": -1799999.999999977} + ], + "line": [ + {"id": 3, "energized": 1, "p_from": 1503299.524795742, "q_from": 872800.3483832447, "i_from": 101.9863546812424, "s_from": 1738300.868488829, "p_to": -1499999.999999964, "q_to": -899999.9999999987, "i_to": 102.8848636288021, "s_to": 1749285.568453559}, + {"id": 4, "energized": 1, "p_from": 3012861.719887234, "q_from": 1782438.622986824, "i_from": 205.382558096777, "s_from": 3500631.826953104, "p_to": -3000000.000000005, "q_to": -1799999.999999977, "i_to": 206.2862254994529, "s_to": 3498571.136907173} + ], + "source": [ + {"id": 5, "energized": 1, "p": 4516161.244682975, "q": 2655238.971370068, "i": 307.3666203361138, "s": 5238893.622040713, "pf": 0.8620448458206694} + ], + "sym_load": [ + {"id": 6, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 102.8848636288039, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 7, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 103.1431127497267, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 8, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 103.1431127497267, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid4-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json new file mode 100644 index 000000000..92185005c --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json @@ -0,0 +1,35 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9717448976529293, 0.9717448976529298, 0.9717448976529274], "u": [5610.371782435641, 5610.371782435644, 5610.37178243563], "u_angle": [-0.03667859182485663, -2.131073694218052, 2.057716510568336], "p": [2541627.503834988, 2541627.50383497, 2541627.503835248], "q": [1541627.503835049, 1541627.503835077, 1541627.50383517]}, + {"id": 1, "energized": 1, "u_pu": [0.9591439187975326, 0.959143918797533, 0.9591439187975291], "u": [5537.619997093479, 5537.619997093482, 5537.61999709346], "u_angle": [-0.03989733227649931, -2.134292434669694, 2.054497770116693], "p": [-499999.999999796, -500000.0000000092, -500000.0000000336], "q": [-299999.9999999094, -299999.9999999169, -300000.0000001056]}, + {"id": 2, "energized": 1, "u_pu": [0.9566349196745317, 0.9566349196745322, 0.9566349196745283], "u": [5523.134283902869, 5523.134283902872, 5523.134283902849], "u_angle": [-0.04055124723789744, -2.134946349631092, 2.053843855155294], "p": [-500000.0000000189, -499999.999999903, -500000.0000000337], "q": [-300000.0000000087, -300000.0000000552, -299999.9999999469]}, + {"id": 3, "energized": 1, "u_pu": [0.951561259333002, 0.9515612593330021, 0.9515612593329975], "u": [5493.84149226328, 5493.84149226328, 5493.841492263254], "u_angle": [-0.04186953818982866, -2.136264640583023, 2.052525564203363], "p": [-499999.9999999431, -499999.9999999345, -499999.9999999151], "q": [-300000.0000000093, -299999.9999999596, -300000.0000000612]}, + {"id": 4, "energized": 1, "u_pu": [0.949032157127342, 0.949032157127342, 0.9490321571273375], "u": [5479.239713870821, 5479.239713870821, 5479.239713870795], "u_angle": [-0.04253394427521901, -2.136929046668413, 2.051861158117972], "p": [-500000.0000000164, -500000.0000000151, -500000.0000000789], "q": [-299999.9999999824, -300000.0000000439, -299999.9999999783]}, + {"id": 5, "energized": 1, "u_pu": [0.949032157127342, 0.949032157127342, 0.9490321571273375], "u": [5479.239713870821, 5479.239713870821, 5479.239713870795], "u_angle": [-0.04253394427521901, -2.136929046668413, 2.051861158117972], "p": [-500000.0000000164, -500000.0000000151, -500000.0000000789], "q": [-299999.9999999824, -300000.0000000439, -299999.9999999783]}, + {"id": 6, "energized": 1, "u_pu": [0.951561259333002, 0.9515612593330021, 0.9515612593329975], "u": [5493.84149226328, 5493.84149226328, 5493.841492263254], "u_angle": [-0.04186953818982869, -2.136264640583023, 2.052525564203363], "p": [0, -0, 0], "q": [-0, 0, 0]} + ], + "line": [ + {"id": 7, "energized": 1, "p_from": [2541627.503834988, 2541627.50383497, 2541627.503835248], "q_from": [1541627.503835049, 1541627.503835077, 1541627.50383517], "i_from": [529.844156027448, 529.8441560274476, 529.8441560274999], "s_from": [2972622.702064821, 2972622.70206482, 2972622.702065106], "p_to": [-2513554.020867344, -2513554.020867326, -2513554.020867599], "q_to": [-1513554.020867405, -1513554.020867433, -1513554.02086752], "i_to": [529.844156027448, 529.8441560274476, 529.8441560274999], "s_to": [2934075.593760714, 2934075.593760712, 2934075.593760991]}, + {"id": 8, "energized": 1, "p_from": [501114.570931692, 501114.570931576, 501114.5709317069], "q_from": [301114.5709316818, 301114.5709317281, 301114.57093162], "i_from": [105.5732414806529, 105.5732414806393, 105.5732414806499], "s_from": [584624.4931812424, 584624.4931811669, 584624.4931812234], "p_to": [-500000.0000000189, -499999.999999903, -500000.0000000337], "q_to": [-300000.0000000087, -300000.0000000552, -299999.9999999469], "i_to": [105.5732414806529, 105.5732414806393, 105.5732414806499], "s_to": [583095.1894845506, 583095.1894844753, 583095.1894845316]}, + {"id": 9, "energized": 1, "p_from": [1512439.449935764, 1512439.449935752, 1512439.449935886], "q_from": [912439.4499357813, 912439.4499358241, 912439.449935819], "i_from": [318.9741273460251, 318.9741273460271, 318.9741273460486], "s_from": [1766357.50614679, 1766357.506146803, 1766357.506146914], "p_to": [-1502265.000544148, -1502265.000544137, -1502265.000544269], "q_to": [-902265.0005441656, -902265.0005442082, -902265.0005442012], "i_to": [318.9741273460251, 318.9741273460271, 318.9741273460486], "s_to": [1752393.295772063, 1752393.295772075, 1752393.295772185]}, + {"id": 10, "energized": 1, "p_from": [501132.5002721119, 501132.5002721106, 501132.5002721746], "q_from": [301132.5002720777, 301132.5002721395, 301132.500272074], "i_from": [106.4189960531232, 106.4189960531288, 106.4189960531332], "s_from": [584649.0960816506, 584649.0960816813, 584649.0960817025], "p_to": [-500000.0000000164, -500000.0000000151, -500000.0000000789], "q_to": [-299999.9999999824, -300000.0000000439, -299999.9999999783], "i_to": [106.4189960531232, 106.4189960531288, 106.4189960531332], "s_to": [583095.189484535, 583095.1894845655, 583095.1894845866]}, + {"id": 11, "energized": 1, "p_from": [501132.5002721119, 501132.5002721106, 501132.5002721746], "q_from": [301132.5002720777, 301132.5002721395, 301132.500272074], "i_from": [106.4189960531232, 106.4189960531288, 106.4189960531332], "s_from": [584649.0960816506, 584649.0960816813, 584649.0960817025], "p_to": [-500000.0000000164, -500000.0000000151, -500000.0000000789], "q_to": [-299999.9999999824, -300000.0000000439, -299999.9999999783], "i_to": [106.4189960531232, 106.4189960531288, 106.4189960531332], "s_to": [583095.189484535, 583095.1894845655, 583095.1894845866]}, + {"id": 12, "energized": 1, "p_from": [0, -0, 0], "q_from": [-0, 0, 0], "i_from": [0, 0, 0], "s_from": [0, 0, 0], "p_to": [0, -0, 0], "q_to": [-0, 0, 0], "i_to": [0, 0, 0], "s_to": [0, 0, 0]} + ], + "source": [ + {"id": 13, "energized": 1, "p": [2541627.503834988, 2541627.50383497, 2541627.503835248], "q": [1541627.50383505, 1541627.503835077, 1541627.50383517], "i": [529.844156027448, 529.8441560274476, 529.8441560274999], "s": [2972622.702064821, 2972622.70206482, 2972622.702065106], "pf": [0.855011805591588, 0.8550118055915825, 0.8550118055915938]} + ], + "sym_load": [ + {"id": 14, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [105.2970752400089, 105.2970752400089, 105.2970752400093], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 15, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [105.5732414806492, 105.5732414806491, 105.5732414806496], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 16, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.1361508710573, 106.1361508710573, 106.1361508710578], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 17, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.4189960531223, 106.4189960531223, 106.4189960531229], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 18, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.4189960531223, 106.4189960531223, 106.4189960531229], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json new file mode 100644 index 000000000..1d03b6e05 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json @@ -0,0 +1,45 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000}, + {"id": 3, "u_rated": 10000}, + {"id": 4, "u_rated": 10000}, + {"id": 5, "u_rated": 10000}, + {"id": 6, "u_rated": 10000} + ], + "line": [ + {"id": 7, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 8, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 9, "from_node": 1, "to_node": 3, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 10, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 11, "from_node": 3, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0}, + {"id": 12, "from_node": 3, "to_node": 6, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 0, "tan1": 0, "r0": 0.15, "x0": 0.15, "c0": 0, "tan0": 0} + ], + "source": [ + {"id": 13, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 14, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 15, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 16, "node": 3, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 17, "node": 4, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 18, "node": 5, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 20, "measured_object": 13, "measured_terminal_type": 2, "power_sigma": 89178.68106194651, "p_measured": 7624882.51150519, "q_measured": 4624882.51150514}, + {"id": 21, "measured_object": 14, "measured_terminal_type": 4, "power_sigma": 89178.68106194651, "p_measured": 1500000, "q_measured": 899999.9999999999}, + {"id": 22, "measured_object": 15, "measured_terminal_type": 4, "power_sigma": 89178.68106194651, "p_measured": 1500000, "q_measured": 899999.9999999999}, + {"id": 23, "measured_object": 10, "measured_terminal_type": 0, "power_sigma": 89178.68106194651, "p_measured": 1503397.500816225, "q_measured": 903397.5008161829}, + {"id": 24, "measured_object": 18, "measured_terminal_type": 4, "power_sigma": 89178.68106194651, "p_measured": 1500000, "q_measured": 899999.9999999999} + ], + "sym_voltage_sensor": [ + {"id": 19, "measured_object": 0, "u_sigma": 10, "u_measured": 9717.448976529296} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json new file mode 100644 index 000000000..44662b61c --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json @@ -0,0 +1,35 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9717448976529297, "u": 9717.448976529296, "u_angle": -0.03667859182485689, "p": 7624882.511505189, "q": 4624882.511505141}, + {"id": 1, "energized": 1, "u_pu": 0.9591439187975328, "u": 9591.439187975328, "u_angle": -0.03989733227649962, "p": -1499999.99999972, "q": -899999.9999998241}, + {"id": 2, "energized": 1, "u_pu": 0.9566349196745321, "u": 9566.349196745321, "u_angle": -0.0405512472378978, "p": -1499999.999999944, "q": -899999.9999999215}, + {"id": 3, "energized": 1, "u_pu": 0.9515612593330015, "u": 9515.612593330015, "u_angle": -0.04186953818982894, "p": -1500000.000000063, "q": -900000.0000004504}, + {"id": 4, "energized": 1, "u_pu": 0.9490321571273418, "u": 9490.321571273418, "u_angle": -0.04253394427521929, "p": -1499999.999999939, "q": -899999.9999998971}, + {"id": 5, "energized": 1, "u_pu": 0.9490321571273418, "u": 9490.321571273418, "u_angle": -0.04253394427521929, "p": -1499999.999999939, "q": -899999.9999998971}, + {"id": 6, "energized": 1, "u_pu": 0.9515612593330015, "u": 9515.612593330015, "u_angle": -0.04186953818982899, "p": -5.177852922559154e-08, "q": 5.630665218686026e-08} + ], + "line": [ + {"id": 7, "energized": 1, "p_from": 7624882.511505189, "q_from": 4624882.511505141, "i_from": 529.844156027459, "s_from": 8917868.106194651, "p_to": -7540662.062602255, "q_to": -4540662.062602206, "i_to": 529.844156027459, "s_to": 8802226.781282324}, + {"id": 8, "energized": 1, "p_from": 1503343.712794963, "q_from": 903343.7127949407, "i_from": 105.5732414806438, "s_from": 1753873.479543577, "p_to": -1499999.999999944, "q_to": -899999.9999999215, "i_to": 105.5732414806438, "s_to": 1749285.568453502}, + {"id": 9, "energized": 1, "p_from": 4537318.349807466, "q_from": 2737318.349807554, "i_from": 318.9741273460405, "s_from": 5299072.518440628, "p_to": -4506795.001632616, "q_to": -2706795.001632704, "i_to": 318.9741273460405, "s_to": 5257179.887316442}, + {"id": 10, "energized": 1, "p_from": 1503397.500816225, "q_from": 903397.5008161829, "i_from": 106.4189960531159, "s_from": 1753947.288244831, "p_to": -1499999.999999939, "q_to": -899999.9999998971, "i_to": 106.4189960531159, "s_to": 1749285.568453485}, + {"id": 11, "energized": 1, "p_from": 1503397.500816225, "q_from": 903397.5008161829, "i_from": 106.4189960531159, "s_from": 1753947.288244831, "p_to": -1499999.999999939, "q_to": -899999.9999998971, "i_to": 106.4189960531159, "s_to": 1749285.568453485}, + {"id": 12, "energized": 1, "p_from": 5.177852922559155e-08, "q_from": -5.630665218686026e-08, "i_from": 4.641245714809236e-12, "s_from": 7.649480485142434e-08, "p_to": -5.177852922559154e-08, "q_to": 5.630665218686026e-08, "i_to": 4.641245714809236e-12, "s_to": 7.649480485142434e-08} + ], + "source": [ + {"id": 13, "energized": 1, "p": 7624882.51150519, "q": 4624882.51150514, "i": 529.8441560274591, "s": 8917868.106194651, "pf": 0.8550118055915955} + ], + "sym_load": [ + {"id": 14, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 105.2970752400089, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 15, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 105.5732414806491, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 16, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.1361508710574, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 17, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.4189960531223, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 18, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.4189960531223, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-no-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json new file mode 100644 index 000000000..72aee3cac --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json @@ -0,0 +1,35 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": [0.9726645995354783, 0.9726645995354793, 0.9726645995354811], "u": [5615.681683730279, 5615.681683730286, 5615.681683730296], "u_angle": [-0.03672507209736713, -2.131120174490559, 2.057670030295831], "p": [2541084.864211002, 2541084.864210833, 2541084.864210915], "q": [1483335.360592719, 1483335.360592685, 1483335.360592571]}, + {"id": 1, "energized": 1, "u_pu": [0.9602423243206472, 0.960242324320649, 0.9602423243206509], "u": [5543.961644337975, 5543.961644337986, 5543.961644337997], "u_angle": [-0.04010659301980082, -2.134501695412993, 2.054288509373397], "p": [-499999.9999999899, -500000.000000044, -499999.9999999983], "q": [-300000.0000000385, -300000.000000245, -300000.0000000871]}, + {"id": 2, "energized": 1, "u_pu": [0.9577512091046109, 0.957751209104613, 0.9577512091046149], "u": [5529.579183932367, 5529.579183932378, 5529.579183932389], "u_angle": [-0.04077474424378581, -2.135169846636978, 2.053620358149411], "p": [-500000.0000000091, -499999.9999999769, -500000.0000000682], "q": [-300000.0000000058, -300000.0000000084, -299999.9999999369]}, + {"id": 3, "energized": 1, "u_pu": [0.9527733391101315, 0.9527733391101343, 0.9527733391101366], "u": [5500.83943811933, 5500.839438119347, 5500.839438119359], "u_angle": [-0.04218351865378789, -2.13657862104698, 2.05221158373941], "p": [-499999.9999999021, -500000.0000000016, -500000.0000000047], "q": [-300000.0000000516, -299999.9999998853, -299999.9999999652]}, + {"id": 4, "energized": 1, "u_pu": [0.9502623535763265, 0.9502623535763294, 0.9502623535763318], "u": [5486.342256380594, 5486.342256380611, 5486.342256380625], "u_angle": [-0.04286196537376114, -2.137257067766953, 2.051533137019437], "p": [-499999.9999999957, -500000.0000000055, -499999.9999999637], "q": [-299999.999999998, -300000.00000007, -299999.9999999836]}, + {"id": 5, "energized": 1, "u_pu": [0.9502623535763265, 0.9502623535763294, 0.9502623535763318], "u": [5486.342256380594, 5486.342256380611, 5486.342256380625], "u_angle": [-0.04286196537376114, -2.137257067766953, 2.051533137019437], "p": [-499999.9999999957, -500000.0000000055, -499999.9999999637], "q": [-299999.999999998, -300000.00000007, -299999.9999999836]}, + {"id": 6, "energized": 1, "u_pu": [0.95278823052212, 0.952788230522123, 0.9527882305221255], "u": [5500.925413726532, 5500.925413726549, 5500.925413726563], "u_angle": [-0.04219930540360874, -2.1365944077968, 2.052195796989589], "p": [-3.759756630622919e-08, -6.130199561547197e-10, 4.179507586572451e-09], "q": [-3.455113276105434e-08, -8.515478845386919e-08, -8.000727876856735e-09]} + ], + "line": [ + {"id": 7, "energized": 1, "p_from": [2541084.864211002, 2541084.864210833, 2541084.864210915], "q_from": [1483335.360592719, 1483335.360592685, 1483335.360592571], "i_from": [523.9515881045714, 523.9515881045421, 523.9515881045432], "s_from": [2942345.336480234, 2942345.336480071, 2942345.336480083], "p_to": [-2513537.15069113, -2513537.150690961, -2513537.150691026], "q_to": [-1465618.122210566, -1465618.122210542, -1465618.122210404], "i_to": [524.8273884851878, 524.8273884851584, 524.8273884851549], "s_to": [2909622.911659948, 2909622.911659789, 2909622.911659776]}, + {"id": 8, "energized": 1, "p_from": [501150.8576588897, 501150.8576588416, 501150.8576589064], "q_from": [291471.8753018776, 291471.875301849, 291471.8753017986], "i_from": [104.5729190869774, 104.5729190869672, 104.5729190869725], "s_from": [579748.2524546615, 579748.2524546057, 579748.2524546364], "p_to": [-500000.0000000091, -499999.9999999769, -500000.0000000682], "q_to": [-300000.0000000058, -300000.0000000084, -299999.9999999369], "i_to": [105.4501925171586, 105.4501925171537, 105.4501925171609], "s_to": [583095.189484541, 583095.1894845145, 583095.1894845561]}, + {"id": 9, "energized": 1, "p_from": [1512386.29303223, 1512386.293032029, 1512386.293032001], "q_from": [874146.2469085958, 874146.2469084773, 874146.2469084344], "i_from": [315.088448919026, 315.0884489189833, 315.0884489189744], "s_from": [1746838.275381025, 1746838.275380792, 1746838.275380746], "p_to": [-1502383.014419183, -1502383.014419024, -1502383.014419025], "q_to": [-873771.905633801, -873771.9056337178, -873771.9056336614], "i_to": [315.9511536429162, 315.9511536428825, 315.9511536428769], "s_to": [1737996.566478252, 1737996.566478073, 1737996.566478046]}, + {"id": 10, "energized": 1, "p_from": [501167.7039579991, 501167.7039579399, 501167.7039579418], "q_from": [291639.0992176569, 291639.0992176839, 291639.0992176362], "i_from": [105.4106214482275, 105.4106214482203, 105.410621448216], "s_from": [579846.903659077, 579846.9036590395, 579846.9036590171], "p_to": [-499999.9999999957, -500000.0000000055, -499999.9999999637], "q_to": [-299999.999999998, -300000.00000007, -299999.9999999836], "i_to": [106.2812274984099, 106.2812274984179, 106.2812274984029], "s_to": [583095.1894845252, 583095.1894845708, 583095.1894844904]}, + {"id": 11, "energized": 1, "p_from": [501167.7039579991, 501167.7039579399, 501167.7039579418], "q_from": [291639.0992176569, 291639.0992176839, 291639.0992176362], "i_from": [105.4106214482275, 105.4106214482203, 105.410621448216], "s_from": [579846.903659077, 579846.9036590395, 579846.9036590171], "p_to": [-499999.9999999957, -500000.0000000055, -499999.9999999637], "q_to": [-299999.999999998, -300000.00000007, -299999.9999999836], "i_to": [106.2812274984099, 106.2812274984179, 106.2812274984029], "s_to": [583095.1894845252, 583095.1894845708, 583095.1894844904]}, + {"id": 12, "energized": 1, "p_from": [47.60650326719226, 47.60650316120984, 47.60650316895364], "q_from": [-9506.292801509433, -9506.29280150464, -9506.292801559241], "i_from": [1.728174783477169, 1.728174783476196, 1.728174783486125], "s_from": [9506.412004914546, 9506.412004909222, 9506.41200496386], "p_to": [-3.759756630622919e-08, -6.130199561547197e-10, 4.179507586572451e-09], "q_to": [-3.455113276105434e-08, -8.515478845386919e-08, -8.000727876856735e-09], "i_to": [9.282491429618473e-12, 1.548048529151268e-11, 1.640928159047308e-12], "s_to": [5.106229300788698e-08, 8.515699495690214e-08, 9.02662341220288e-09]} + ], + "source": [ + {"id": 13, "energized": 1, "p": [2541084.864211002, 2541084.864210833, 2541084.864210915], "q": [1483335.360592719, 1483335.360592685, 1483335.360592571], "i": [523.9515881045714, 523.9515881045419, 523.9515881045432], "s": [2942345.336480234, 2942345.33648007, 2942345.336480083], "pf": [0.8636256365647283, 0.8636256365647189, 0.8636256365647431]} + ], + "sym_load": [ + {"id": 14, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [105.1766276341473, 105.1766276341471, 105.1766276341469], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 15, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [105.4501925171567, 105.4501925171564, 105.4501925171562], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 16, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.0011287447945, 106.0011287447942, 106.0011287447939], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 17, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.2812274984108, 106.2812274984104, 106.2812274984102], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]}, + {"id": 18, "energized": 1, "p": [500000, 500000, 500000], "q": [299999.9999999999, 299999.9999999999, 299999.9999999999], "i": [106.2812274984108, 106.2812274984104, 106.2812274984102], "s": [583095.1894845299, 583095.1894845299, 583095.1894845299], "pf": [0.8574929257125444, 0.8574929257125444, 0.8574929257125444]} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json new file mode 100644 index 000000000..a078d4593 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json @@ -0,0 +1,45 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000}, + {"id": 3, "u_rated": 10000}, + {"id": 4, "u_rated": 10000}, + {"id": 5, "u_rated": 10000}, + {"id": 6, "u_rated": 10000} + ], + "line": [ + {"id": 7, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 8, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 9, "from_node": 1, "to_node": 3, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 10, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 11, "from_node": 3, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005}, + {"id": 12, "from_node": 3, "to_node": 6, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.1, "c1": 1e-06, "tan1": 0.005, "r0": 0.15, "x0": 0.15, "c0": 5e-07, "tan0": 0.005} + ], + "source": [ + {"id": 13, "node": 0, "status": 1, "u_ref": 1, "sk": 200000000} + ], + "sym_load": [ + {"id": 14, "node": 1, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 15, "node": 2, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 16, "node": 3, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 17, "node": 4, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000}, + {"id": 18, "node": 5, "status": 1, "type": 0, "p_specified": 1500000, "q_specified": 900000} + ], + "sym_power_sensor": [ + {"id": 20, "measured_object": 13, "measured_terminal_type": 2, "power_sigma": 88270.36009440178, "p_measured": 7623254.592632667, "q_measured": 4450006.081777699}, + {"id": 21, "measured_object": 14, "measured_terminal_type": 4, "power_sigma": 88270.36009440178, "p_measured": 1500000, "q_measured": 899999.9999999999}, + {"id": 22, "measured_object": 15, "measured_terminal_type": 4, "power_sigma": 88270.36009440178, "p_measured": 1500000, "q_measured": 899999.9999999999}, + {"id": 23, "measured_object": 10, "measured_terminal_type": 0, "power_sigma": 88270.36009440178, "p_measured": 1503503.111873887, "q_measured": 874917.2976528193}, + {"id": 24, "measured_object": 18, "measured_terminal_type": 4, "power_sigma": 88270.36009440178, "p_measured": 1500000, "q_measured": 899999.9999999999} + ], + "sym_voltage_sensor": [ + {"id": 19, "measured_object": 0, "u_sigma": 10, "u_measured": 9726.645995354807} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json new file mode 100644 index 000000000..e441bb417 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json @@ -0,0 +1,11 @@ +{ + "calculation_method": [ + "newton_raphson", + "iterative_linear" + ], + "rtol": 1e-08, + "atol": { + "default": 1e-06, + ".+_residual": 0.0001 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json new file mode 100644 index 000000000..72893d5fd --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json @@ -0,0 +1,35 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 0.9726645995354807, "u": 9726.645995354807, "u_angle": -0.0367250720973653, "p": 7623254.592632666, "q": 4450006.081777698}, + {"id": 1, "energized": 1, "u_pu": 0.9602423243206505, "u": 9602.423243206506, "u_angle": -0.040106593019799, "p": -1499999.999999978, "q": -900000.0000002306}, + {"id": 2, "energized": 1, "u_pu": 0.9577512091046144, "u": 9577.512091046145, "u_angle": -0.04077474424378402, "p": -1499999.999999918, "q": -899999.9999999192}, + {"id": 3, "energized": 1, "u_pu": 0.9527733391101356, "u": 9527.733391101356, "u_angle": -0.04218351865378603, "p": -1499999.999999871, "q": -900000.0000001004}, + {"id": 4, "energized": 1, "u_pu": 0.9502623535763308, "u": 9502.623535763309, "u_angle": -0.04286196537375931, "p": -1499999.999999936, "q": -899999.999999949}, + {"id": 5, "energized": 1, "u_pu": 0.9502623535763308, "u": 9502.623535763309, "u_angle": -0.04286196537375931, "p": -1499999.999999936, "q": -899999.999999949}, + {"id": 6, "energized": 1, "u_pu": 0.9527882305221245, "u": 9527.882305221245, "u_angle": -0.04219930540360684, "p": 5.411152430046291e-08, "q": -2.284825158881043e-09} + ], + "line": [ + {"id": 7, "energized": 1, "p_from": 7623254.592632666, "q_from": 4450006.081777698, "i_from": 523.951588104539, "s_from": 8827036.009440176, "p_to": -7540611.452073002, "q_to": -4396854.366631142, "i_to": 524.8273884851491, "s_to": 8728868.734979225}, + {"id": 8, "energized": 1, "p_from": 1503452.572976561, "q_from": 874415.6259055883, "i_from": 104.5729190869701, "s_from": 1739244.757363869, "p_to": -1499999.999999918, "q_to": -899999.9999999192, "i_to": 105.4501925171495, "s_to": 1749285.568453478}, + {"id": 9, "energized": 1, "p_from": 4537158.879096254, "q_from": 2622438.740725549, "i_from": 315.088448918995, "s_from": 5240514.826142578, "p_to": -4507149.043257174, "q_to": -2621315.716901168, "i_to": 315.951153642888, "s_to": 5213989.699434316}, + {"id": 10, "energized": 1, "p_from": 1503503.111873887, "q_from": 874917.2976528193, "i_from": 105.4106214482166, "s_from": 1739540.71097706, "p_to": -1499999.999999936, "q_to": -899999.999999949, "i_to": 106.2812274984053, "s_to": 1749285.568453509}, + {"id": 11, "energized": 1, "p_from": 1503503.111873887, "q_from": 874917.2976528193, "i_from": 105.4106214482166, "s_from": 1739540.71097706, "p_to": -1499999.999999936, "q_to": -899999.999999949, "i_to": 106.2812274984053, "s_to": 1749285.568453509}, + {"id": 12, "energized": 1, "p_from": 142.8195096324467, "q_from": -28518.8784046839, "i_from": 1.728174783486539, "s_from": 28519.23601489839, "p_to": 5.411152430046291e-08, "q_to": -2.284825158881043e-09, "i_to": 3.281856318094616e-12, "s_to": 5.415974047321722e-08} + ], + "source": [ + {"id": 13, "energized": 1, "p": 7623254.592632667, "q": 4450006.081777699, "i": 523.9515881045392, "s": 8827036.009440178, "pf": 0.8636256365647412} + ], + "sym_load": [ + {"id": 14, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 105.1766276341469, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 15, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 105.4501925171563, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 16, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.001128744794, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 17, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.2812274984103, "s": 1749285.56845359, "pf": 0.8574929257125443}, + {"id": 18, "energized": 1, "p": 1500000, "q": 899999.9999999999, "i": 106.2812274984103, "s": 1749285.56845359, "pf": 0.8574929257125443} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/grid5-with-capacitance/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json new file mode 100644 index 000000000..670354065 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json @@ -0,0 +1,30 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10}, + {"id": 1, "u_rated": 10}, + {"id": 7, "u_rated": 10} + ], + "line": [ + {"id": 2, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 2.0, "x1": 0.0, "c1": 0.0, "tan1": 0.0, "i_n": 500}, + {"id": 8, "from_node": 0, "to_node": 7, "from_status": 1, "to_status": 1, "r1": 1.0, "x1": 0.0, "c1": 0.0, "tan1": 0.0, "i_n": 500}, + {"id": 9, "from_node": 7, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 1.0, "x1": 0.0, "c1": 0.0, "tan1": 0.0, "i_n": 500} + ], + "source": [ + {"id": 3, "node": 0, "status": 1, "u_ref": 1.0} + ], + "sym_load": [ + {"id": 4, "node": 1, "status": 1, "type": 0, "p_specified": 9, "q_specified": 0} + ], + "sym_power_sensor": [ + {"id": 5, "measured_object": 3, "measured_terminal_type": 2, "power_sigma": 1, "p_measured": 10, "q_measured": 0} + ], + "sym_voltage_sensor": [ + {"id": 6, "measured_object": 0, "u_sigma": 1, "u_measured": 10} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/leaf-without-power-sensor/params.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json similarity index 78% rename from tests/data/state_estimation/leaf-without-power-sensor/params.json rename to tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json index 4167e1fbf..94b091fd3 100644 --- a/tests/data/state_estimation/leaf-without-power-sensor/params.json +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json @@ -7,6 +7,6 @@ }, "fail": { "raises": "SparseMatrixError", - "reason": "Bug in Sparse LU solver found in #853" + "reason": "Bug in Sparse LU solver found in #864" } } \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json new file mode 100644 index 000000000..fd287e598 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "energized": 1, "u_pu": 1, "u": 10, "u_angle": 0}, + {"id": 1, "energized": 1, "u_pu": 0.9, "u": 9, "u_angle": 0} + ], + "source": [ + {"id": 3, "energized": 1, "p": 10, "q": 0} + ], + "sym_load": [ + {"id": 4, "energized": 1, "p": 9, "q": 0} + ], + "sym_power_sensor": [ + {"id": 5, "energized": 1, "p_residual": 0, "q_residual": 0} + ], + "sym_voltage_sensor": [ + {"id": 6, "energized": 1, "u_residual": 0} + ] + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor-meshed/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/leaf-without-power-sensor/input.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/input.json similarity index 100% rename from tests/data/state_estimation/leaf-without-power-sensor/input.json rename to tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/input.json diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/input.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/middle-without-power-sensor/params.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json similarity index 57% rename from tests/data/state_estimation/middle-without-power-sensor/params.json rename to tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json index 4167e1fbf..a0e22b030 100644 --- a/tests/data/state_estimation/middle-without-power-sensor/params.json +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json @@ -4,9 +4,5 @@ "atol": { "default": 1e-8, ".+_residual": 5e-4 - }, - "fail": { - "raises": "SparseMatrixError", - "reason": "Bug in Sparse LU solver found in #853" } } \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/leaf-without-power-sensor/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/sym_output.json similarity index 100% rename from tests/data/state_estimation/leaf-without-power-sensor/sym_output.json rename to tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/sym_output.json diff --git a/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/leaf-without-power-sensor/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/middle-without-power-sensor/input.json b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/input.json similarity index 100% rename from tests/data/state_estimation/middle-without-power-sensor/input.json rename to tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/input.json diff --git a/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/input.json.license b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json new file mode 100644 index 000000000..a0e22b030 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json @@ -0,0 +1,8 @@ +{ + "calculation_method": ["newton_raphson", "iterative_linear"], + "rtol": 1e-8, + "atol": { + "default": 1e-8, + ".+_residual": 5e-4 + } +} \ No newline at end of file diff --git a/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json.license b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/state_estimation/middle-without-power-sensor/sym_output.json b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json similarity index 92% rename from tests/data/state_estimation/middle-without-power-sensor/sym_output.json rename to tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json index 9ea2249f5..572ffefb3 100644 --- a/tests/data/state_estimation/middle-without-power-sensor/sym_output.json +++ b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json @@ -20,7 +20,8 @@ {"id": 4, "energized": 1, "p": 9, "q": 0} ], "sym_power_sensor": [ - {"id": 5, "energized": 1, "p_residual": 0, "q_residual": 0} + {"id": 5, "energized": 1, "p_residual": 0, "q_residual": 0}, + {"id": 9, "energized": 1, "p_residual": 0, "q_residual": 0} ], "sym_voltage_sensor": [ {"id": 6, "energized": 1, "u_residual": 0} diff --git a/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json.license b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/state_estimation/ill-conditioned-system/middle-without-power-sensor/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/unit/test_serialization.py b/tests/unit/test_serialization.py index c805c3881..a7cc2663a 100644 --- a/tests/unit/test_serialization.py +++ b/tests/unit/test_serialization.py @@ -11,7 +11,7 @@ from power_grid_model import DatasetType from power_grid_model._utils import get_dataset_type, is_columnar, is_sparse -from power_grid_model.data_types import BatchDataset, Dataset, SingleDataset +from power_grid_model.data_types import BatchDataset, Dataset, DenseBatchData, SingleComponentData, SingleDataset from power_grid_model.enum import ComponentAttributeFilterOptions from power_grid_model.utils import json_deserialize, json_serialize, msgpack_deserialize, msgpack_serialize @@ -617,10 +617,10 @@ def assert_serialization_correct(deserialized_dataset: Dataset, serialized_datas ) -def _check_only_relevant_attributes_present(component_values) -> bool: +def _check_only_relevant_attributes_present(component_values: SingleComponentData | DenseBatchData) -> bool: + if isinstance(component_values, np.ndarray): + return True for array in component_values.values(): - if not isinstance(array, np.ndarray): - continue if (array.dtype == np.float64 and np.isnan(array).all()) or ( array.dtype in (np.int32, np.int8) and np.all(array == np.iinfo(array.dtype).min) ): @@ -633,7 +633,8 @@ def assert_deserialization_filtering_correct(deserialized_dataset: Dataset, data return True if data_filter is ComponentAttributeFilterOptions.relevant: for component_values in deserialized_dataset.values(): - if not _check_only_relevant_attributes_present(component_values): + buffer = component_values if not is_sparse(component_values) else component_values["data"] + if not _check_only_relevant_attributes_present(buffer): return False return True diff --git a/tests/unit/utils.py b/tests/unit/utils.py index c443d89d0..afab0e4f0 100644 --- a/tests/unit/utils.py +++ b/tests/unit/utils.py @@ -26,6 +26,7 @@ InvalidMeasuredObject, InvalidRegulatedObject, InvalidTransformerClock, + MaxIterationReached, NotObservableError, PowerGridBatchError, PowerGridError, @@ -62,6 +63,7 @@ PowerGridSerializationError, AssertionError, OSError, + MaxIterationReached, ) } diff --git a/tests/unit/validation/test_batch_validation.py b/tests/unit/validation/test_batch_validation.py index 064f9853d..5d976e513 100644 --- a/tests/unit/validation/test_batch_validation.py +++ b/tests/unit/validation/test_batch_validation.py @@ -6,19 +6,19 @@ import numpy as np import pytest -from power_grid_model import DatasetType, LoadGenType, initialize_array +from power_grid_model import ComponentType, DatasetType, LoadGenType, initialize_array from power_grid_model._utils import compatibility_convert_row_columnar_dataset, is_columnar from power_grid_model.enum import ComponentAttributeFilterOptions from power_grid_model.validation import validate_batch_data -from power_grid_model.validation.errors import MultiComponentNotUniqueError, NotBooleanError +from power_grid_model.validation.errors import MultiComponentNotUniqueError, NotBetweenOrAtError, NotBooleanError @pytest.fixture def original_input_data() -> dict[str, np.ndarray]: - node = initialize_array("input", "node", 4) + node = initialize_array(DatasetType.input, ComponentType.node, 4) node["id"] = [1, 2, 3, 4] node["u_rated"] = 10.5e3 - line = initialize_array("input", "line", 4) + line = initialize_array(DatasetType.input, ComponentType.line, 4) line["id"] = [5, 6, 7, 8] line["from_node"] = [1, 2, 3, 1] @@ -31,7 +31,7 @@ def original_input_data() -> dict[str, np.ndarray]: line["tan1"] = 4.0 line["i_n"] = 5.0 - asym_load = initialize_array("input", "asym_load", 2) + asym_load = initialize_array(DatasetType.input, ComponentType.asym_load, 2) asym_load["id"] = [9, 10] asym_load["node"] = [1, 2] asym_load["status"] = [1, 1] @@ -39,13 +39,19 @@ def original_input_data() -> dict[str, np.ndarray]: asym_load["p_specified"] = [[11e6, 12e6, 13e6], [21e6, 22e6, 23e6]] asym_load["q_specified"] = [[11e5, 12e5, 13e5], [21e5, 22e5, 23e5]] - return {"node": node, "line": line, "asym_load": asym_load} + return { + ComponentType.node: node, + ComponentType.line: line, + ComponentType.asym_load: asym_load, + } @pytest.fixture def original_input_data_columnar_all(original_input_data): return compatibility_convert_row_columnar_dataset( - original_input_data, ComponentAttributeFilterOptions.everything, DatasetType.input + original_input_data, + ComponentAttributeFilterOptions.everything, + DatasetType.input, ) @@ -57,7 +63,11 @@ def original_input_data_columnar_relevant(original_input_data): @pytest.fixture( - params=["original_input_data", "original_input_data_columnar_all", "original_input_data_columnar_relevant"] + params=[ + "original_input_data", + "original_input_data_columnar_all", + "original_input_data_columnar_relevant", + ] ) def input_data(request): return request.getfixturevalue(request.param) @@ -65,12 +75,12 @@ def input_data(request): @pytest.fixture def original_batch_data() -> dict[str, np.ndarray]: - line = initialize_array("update", "line", (3, 2)) + line = initialize_array(DatasetType.update, ComponentType.line, (3, 2)) line["id"] = [[5, 6], [6, 7], [7, 5]] line["from_status"] = [[1, 1], [1, 1], [1, 1]] # Add batch for asym_load, which has 2-D array for p_specified - asym_load = initialize_array("update", "asym_load", (3, 2)) + asym_load = initialize_array(DatasetType.update, ComponentType.asym_load, (3, 2)) asym_load["id"] = [[9, 10], [9, 10], [9, 10]] return {"line": line, "asym_load": asym_load} @@ -79,19 +89,27 @@ def original_batch_data() -> dict[str, np.ndarray]: @pytest.fixture def original_batch_data_columnar_all(original_batch_data): return compatibility_convert_row_columnar_dataset( - original_batch_data, ComponentAttributeFilterOptions.everything, DatasetType.update + original_batch_data, + ComponentAttributeFilterOptions.everything, + DatasetType.update, ) @pytest.fixture def original_batch_data_columnar_relevant(original_batch_data): return compatibility_convert_row_columnar_dataset( - original_batch_data, ComponentAttributeFilterOptions.relevant, DatasetType.update + original_batch_data, + ComponentAttributeFilterOptions.relevant, + DatasetType.update, ) @pytest.fixture( - params=["original_batch_data", "original_batch_data_columnar_all", "original_batch_data_columnar_relevant"] + params=[ + "original_batch_data", + "original_batch_data_columnar_all", + "original_batch_data_columnar_relevant", + ] ) def batch_data(request): return request.getfixturevalue(request.param) @@ -119,7 +137,50 @@ def test_validate_batch_data_input_error(input_data, batch_data): def test_validate_batch_data_update_error(input_data, batch_data): batch_data["line"]["from_status"] = np.array([[12, 34], [0, -128], [56, 78]]) errors = validate_batch_data(input_data, batch_data) - assert len(errors) == 3 - assert NotBooleanError("line", "from_status", [5, 6]) == errors[0][0] - assert NotBooleanError("line", "from_status", [5, 7]) == errors[1][1] - assert NotBooleanError("line", "from_status", [5, 6]) == errors[2][0] + assert len(errors) == 2 + assert 1 not in errors + assert len(errors[0]) == 1 + assert len(errors[2]) == 1 + assert errors[0] == [NotBooleanError("line", "from_status", [5, 6])] + assert errors[2] == [NotBooleanError("line", "from_status", [5, 7])] + + +def test_validate_batch_data_transformer_tap_nom(): + node_input = initialize_array(DatasetType.input, ComponentType.node, 2) + node_input["id"] = [1, 2] + node_input["u_rated"] = [400, 10500] + + transformer_input = initialize_array(DatasetType.input, ComponentType.transformer, 1) + transformer_input["id"] = 3 + transformer_input["from_node"] = 1 + transformer_input["to_node"] = 2 + transformer_input["from_status"] = 1 + transformer_input["to_status"] = 1 + transformer_input["u1"] = 10750 + transformer_input["u2"] = 420 + transformer_input["sn"] = 400000 + transformer_input["uk"] = 0.04 + transformer_input["pk"] = 3750 + transformer_input["i0"] = 0.002230015414744929 + transformer_input["p0"] = 515 + transformer_input["winding_from"] = 2 + transformer_input["winding_to"] = 1 + transformer_input["clock"] = 5 + transformer_input["tap_side"] = 0 + transformer_input["tap_pos"] = 1 + transformer_input["tap_min"] = 1 + transformer_input["tap_max"] = 5 + transformer_input["tap_size"] = 250 + test_input_data = { + ComponentType.node: node_input, + ComponentType.transformer: transformer_input, + } + test_update_data = {ComponentType.sym_load: initialize_array(DatasetType.update, ComponentType.sym_load, (2, 0))} + result = validate_batch_data(test_input_data, test_update_data) + assert result is not None + assert len(result) == test_update_data[ComponentType.sym_load].shape[0] + assert len(result[0]) == test_input_data[ComponentType.transformer].shape[0] + assert len(result[1]) == test_input_data[ComponentType.transformer].shape[0] + + error = NotBetweenOrAtError(ComponentType.transformer, "tap_nom", [3], ("tap_min", "tap_max")) + assert result == {0: [error], 1: [error]}