gridstate 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gridstate-2.0.0 → gridstate-2.1.0}/CHANGELOG.md +13 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/PKG-INFO +1 -1
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/__init__.py +2 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/_version.py +3 -3
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/api.py +8 -2
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/result.py +32 -1
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/PKG-INFO +1 -1
- gridstate-2.1.0/gridstate.egg-info/scm_version.json +8 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_result_quality_summary.py +36 -0
- gridstate-2.0.0/gridstate.egg-info/scm_version.json +0 -8
- {gridstate-2.0.0 → gridstate-2.1.0}/.github/workflows/ci.yml +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/.github/workflows/release.yml +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/.gitignore +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/.pre-commit-config.yaml +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/LICENSE +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/Makefile +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/README.md +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/build_cython.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/__pyinstaller/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/__pyinstaller/hook-gridstate.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/_arrays.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/adapters/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/adapters/from_pandapower.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/_selinv_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/base.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/estimators.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/jacobian_pattern.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algebra/normalized_residuals.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/_gram_numba.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/ipm.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/kkt_solver.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/status.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/algorithms/wls.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/bad_data_repass.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/bounds.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/constants.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/_legacy.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/containers.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/derived.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/derived_tables.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/serialize.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/tables.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/validate.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/contract/version.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/losses.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/measurement_ids.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/config.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/context.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/manifest.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/orchestration.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/passes.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/preparation.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/runner.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/pipeline/steps.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/post_processing.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/_scan.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/ipm_setup.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/meas_rows.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/mirror_voltage.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/node_props.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/preprocessing/pseudo_measurements.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/py.typed +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/quality_summary.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/resolve_pass.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/runtime.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/shunt_sanity.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/state.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/_filters.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/apply_resolved.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/generators.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/kinds.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/load_only_injection.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/loss_filter.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/measurements.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/noise.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/on_line.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/quality.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/rpn.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/shunts.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/sigma_floor.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/units.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/voltage_filter.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/telemetry/voltage_nominal.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/topology.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/units.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/utils.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/v_mirror.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/v_refine.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/validation/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/validation/_diagnostics.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/validation/bad_data.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/validation/chi2_test.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/validation/observability.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/working.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/ybus.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate/z_vector.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/SOURCES.txt +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/dependency_links.txt +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/entry_points.txt +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/requires.txt +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/scm_file_list.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/gridstate.egg-info/top_level.txt +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/pyproject.toml +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/setup.cfg +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/__init__.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/_golden.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/conftest.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_adapters_lazy_import.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_aggregate_generators.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_algebra_base.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_anti_overshoot.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_arrays_helpers.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_bad_data.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_bad_data_repass.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_bounds.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_boxed_balance.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_breaker_reactance.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_chain_mirror.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_contract.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_contract_edge_cases.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_contract_runtime.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case118.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case118.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case118_degraded.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case118_degraded.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case14.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case14.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case14_degraded.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case14_degraded.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case30.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case30.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case30_degraded.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/case30_degraded.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/golden/manifest.json +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case118.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case118_truth.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case14.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case14_truth.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case30.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_data/ieee/case30_truth.npz +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_derived_tables.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_enum_codes.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_flow_sigma_floor.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_from_pandapower.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_generator_shunt_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_golden.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_gram_numba.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_ieee_cases.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_ipm.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_ipm_integration.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_jacobian_pattern.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_kkt_solver.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_load_only_injection.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_losses_breakdown.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_losses_q_convention.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_losses_trafo_classification.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_materialize_kernel.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_measurement_filter_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_measurement_ids.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_mirror_voltage_kernel.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_near_critical_ranking.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_neutral_wording.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_noise_model.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_normalized_residuals.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_numpy_only_runtime.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_observability.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_on_line_kernel.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_perf_synthetic_network.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_config_validation.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_idempotent.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_invariant_errors.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_step_order.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_warm_start.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pipeline_working_layer.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_post_processing.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_preparation_steps.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_prepare_network.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pseudo_unknown_load.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_pseudo_v_unobservable.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_quality_summary_paths.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_reconcile_balance.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_refine_merge.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_resolve_pass.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_rn_selected_inversion.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_serialize_npz.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_shunt_sanity.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_solve_status.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_state.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_state_range.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_telemetry_apply_kernel.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_telemetry_physics_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_tm_code_quality.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_topology_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_topology_port.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_transformer_from_shunt.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_units.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_units_array_kernels.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_v_mirror.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_v_refine.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_variance_charging.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_version.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_voltage_calibration_gen_nodes.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_voltage_range_filter_fallback.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_wls.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_wls_robustness.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_working_container.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_ybus.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tests/test_z_vector.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tools/gen_ieee_fixtures.py +0 -0
- {gridstate-2.0.0 → gridstate-2.1.0}/tools/golden.py +0 -0
|
@@ -9,6 +9,19 @@ types of the merged pull requests; breaking and behavior-changing items are
|
|
|
9
9
|
listed separately under "Breaking changes" and "Behavior changes". A release is
|
|
10
10
|
cut by tagging the merged main commit; the version is derived from that tag.
|
|
11
11
|
|
|
12
|
+
## v2.1.0 (2026-10-14)
|
|
13
|
+
|
|
14
|
+
### Feat
|
|
15
|
+
|
|
16
|
+
- `SEResult.normalized_residuals` (`MeasurementNormalizedResiduals`, exported
|
|
17
|
+
from the package root): `r_N` and `Ω_ii / σ²_i` of every z-vector
|
|
18
|
+
measurement by measurement id, in z-vector order. The quality summary keeps
|
|
19
|
+
the vector it already computes; `worst_residuals` and
|
|
20
|
+
`near_critical_measurements` still rank and trim it. Rows outside the
|
|
21
|
+
residual scope (pseudo-measurements under `"real"`) hold `nan`, critical
|
|
22
|
+
measurements `inf`; `None` when the summary is not computed. Additive, no
|
|
23
|
+
data contract change (#101)
|
|
24
|
+
|
|
12
25
|
## v2.0.0 (2026-10-10)
|
|
13
26
|
|
|
14
27
|
### Breaking changes
|
|
@@ -34,6 +34,7 @@ from gridstate.pipeline import (
|
|
|
34
34
|
from gridstate.result import (
|
|
35
35
|
Chi2Summary,
|
|
36
36
|
ImbalanceRow,
|
|
37
|
+
MeasurementNormalizedResiduals,
|
|
37
38
|
NearCriticalRow,
|
|
38
39
|
ResidualRow,
|
|
39
40
|
SEResult,
|
|
@@ -84,6 +85,7 @@ __all__ = [
|
|
|
84
85
|
"Chi2Summary",
|
|
85
86
|
"ImbalanceRow",
|
|
86
87
|
"InitialPoint",
|
|
88
|
+
"MeasurementNormalizedResiduals",
|
|
87
89
|
"NearCriticalRow",
|
|
88
90
|
"NormalizedResidualReport",
|
|
89
91
|
"ObservabilityReport",
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 1, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g2560497db'
|
|
@@ -39,7 +39,7 @@ from gridstate.quality_summary import (
|
|
|
39
39
|
top_worst_imbalance,
|
|
40
40
|
top_worst_residuals,
|
|
41
41
|
)
|
|
42
|
-
from gridstate.result import SEResult, extract_output_tables
|
|
42
|
+
from gridstate.result import MeasurementNormalizedResiduals, SEResult, extract_output_tables
|
|
43
43
|
from gridstate.state import (
|
|
44
44
|
InitialPoint,
|
|
45
45
|
StateLayout,
|
|
@@ -414,7 +414,8 @@ def _populate_quality_summary(
|
|
|
414
414
|
near_critical: float = NEAR_CRITICAL_THRESHOLD,
|
|
415
415
|
) -> None:
|
|
416
416
|
"""Fill ``result.chi2 / worst_residuals / worst_imbalance /
|
|
417
|
-
observability_warnings / near_critical_measurements
|
|
417
|
+
observability_warnings / near_critical_measurements /
|
|
418
|
+
normalized_residuals`` after
|
|
418
419
|
``write_results_to_model``.
|
|
419
420
|
|
|
420
421
|
All errors in the summary are swallowed into the logs: report quality is not an indicator of
|
|
@@ -476,6 +477,11 @@ def _populate_quality_summary(
|
|
|
476
477
|
is_pseudo=is_pseudo_z,
|
|
477
478
|
network_pu=network_pu,
|
|
478
479
|
)
|
|
480
|
+
result.normalized_residuals = MeasurementNormalizedResiduals(
|
|
481
|
+
measurement_id=np.asarray(meas_index.meas_id, dtype=np.int64).copy(),
|
|
482
|
+
normalized_residual=np.asarray(normalized.rn, dtype=np.float64).copy(),
|
|
483
|
+
omega_ratio=np.asarray(normalized.omega_ratio, dtype=np.float64).copy(),
|
|
484
|
+
)
|
|
479
485
|
result.worst_imbalance = top_worst_imbalance(model, n=top_n)
|
|
480
486
|
result.observability_warnings = observability_warnings_from_H(
|
|
481
487
|
H,
|
|
@@ -13,7 +13,8 @@ canonical Output contract for external adapters (UI/CLI): they join Input +
|
|
|
13
13
|
p.u./radians — for debugging and tests.
|
|
14
14
|
|
|
15
15
|
The additional quality fields (``chi2``, ``worst_residuals``,
|
|
16
|
-
``worst_imbalance``, ``observability_warnings``) are
|
|
16
|
+
``worst_imbalance``, ``observability_warnings``, ``normalized_residuals``) are
|
|
17
|
+
filled by ``estimate()``
|
|
17
18
|
after ``write_results_to_model``: a structured summary for backward-compatible
|
|
18
19
|
diagnostics (it used to be assembled ad hoc by an example script).
|
|
19
20
|
"""
|
|
@@ -119,6 +120,31 @@ class ResidualRow:
|
|
|
119
120
|
is_pseudo: bool = False
|
|
120
121
|
|
|
121
122
|
|
|
123
|
+
@dataclass
|
|
124
|
+
class MeasurementNormalizedResiduals:
|
|
125
|
+
"""Normalized residuals of every z-vector measurement, by measurement id.
|
|
126
|
+
|
|
127
|
+
The full vector behind ``worst_residuals`` / ``near_critical_measurements``:
|
|
128
|
+
those lists rank and trim it, this one keeps every row so that an adapter
|
|
129
|
+
can show ``r_N`` next to each measurement. Arrays are parallel, in z-vector
|
|
130
|
+
order; pseudo-measurements are in the vector only under
|
|
131
|
+
``quality_summary_scope="all"``.
|
|
132
|
+
|
|
133
|
+
Attributes:
|
|
134
|
+
measurement_id: (m,) ``Measurement.id`` of the z-vector rows.
|
|
135
|
+
normalized_residual: (m,) ``|r| / √Ω_ii``; ``inf`` for a critical
|
|
136
|
+
measurement (numerically non-positive ``Ω_ii``); ``nan`` for a row
|
|
137
|
+
outside the residual scope (a pseudo-measurement under ``"real"``).
|
|
138
|
+
omega_ratio: (m,) ``Ω_ii / σ²_i`` (1: fully redundant, 0: critical);
|
|
139
|
+
below the near-critical threshold ``r_N`` is numerically
|
|
140
|
+
unreliable. ``nan`` where ``normalized_residual`` is ``nan``.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
measurement_id: np.ndarray
|
|
144
|
+
normalized_residual: np.ndarray
|
|
145
|
+
omega_ratio: np.ndarray
|
|
146
|
+
|
|
147
|
+
|
|
122
148
|
@dataclass
|
|
123
149
|
class NearCriticalRow:
|
|
124
150
|
"""A measurement whose ``Ω_ii`` is a small fraction of its variance.
|
|
@@ -316,6 +342,10 @@ class SEResult:
|
|
|
316
342
|
``False``; with ``quality_summary_scope="all"`` they take part
|
|
317
343
|
and are marked by ``is_pseudo`` (the pipeline always uses
|
|
318
344
|
``"real"``).
|
|
345
|
+
normalized_residuals: ``r_N`` and ``Ω_ii / σ²_i`` of every z-vector
|
|
346
|
+
measurement (:class:`MeasurementNormalizedResiduals`), the
|
|
347
|
+
untrimmed source of ``worst_residuals``; ``None`` if the summary
|
|
348
|
+
was not computed.
|
|
319
349
|
"""
|
|
320
350
|
|
|
321
351
|
model: Working
|
|
@@ -353,6 +383,7 @@ class SEResult:
|
|
|
353
383
|
worst_imbalance: list[ImbalanceRow] = field(default_factory=list)
|
|
354
384
|
observability_warnings: list[int] = field(default_factory=list)
|
|
355
385
|
near_critical_measurements: list[NearCriticalRow] = field(default_factory=list)
|
|
386
|
+
normalized_residuals: MeasurementNormalizedResiduals | None = None
|
|
356
387
|
|
|
357
388
|
|
|
358
389
|
def label_for_kind(kind_code: int) -> str:
|
|
@@ -19,6 +19,7 @@ from gridstate.api import estimate
|
|
|
19
19
|
from gridstate.result import (
|
|
20
20
|
Chi2Summary,
|
|
21
21
|
ImbalanceRow,
|
|
22
|
+
MeasurementNormalizedResiduals,
|
|
22
23
|
ResidualRow,
|
|
23
24
|
SEResult,
|
|
24
25
|
)
|
|
@@ -96,6 +97,7 @@ def test_seresult_quality_summary_disabled() -> None:
|
|
|
96
97
|
assert res.worst_residuals == []
|
|
97
98
|
assert res.worst_imbalance == []
|
|
98
99
|
assert res.observability_warnings == []
|
|
100
|
+
assert res.normalized_residuals is None
|
|
99
101
|
|
|
100
102
|
|
|
101
103
|
def test_seresult_backward_compat_default_construction() -> None:
|
|
@@ -186,3 +188,37 @@ def test_worst_residuals_scope_all_keeps_pseudo() -> None:
|
|
|
186
188
|
top = res.worst_residuals[0]
|
|
187
189
|
assert top.measurement_id == 900
|
|
188
190
|
assert top.is_pseudo is True
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_normalized_residuals_vector_covers_every_measurement() -> None:
|
|
194
|
+
"""The full r_N vector holds every z row and agrees with the trimmed top."""
|
|
195
|
+
m, _, _ = _three_bus_with_clean_measurements()
|
|
196
|
+
res = estimate(m, tolerance=1e-10, quality_summary_top_n=2)
|
|
197
|
+
|
|
198
|
+
vec = res.normalized_residuals
|
|
199
|
+
assert isinstance(vec, MeasurementNormalizedResiduals)
|
|
200
|
+
n_meas = sum(1 for me in m.measurements if me.status)
|
|
201
|
+
assert vec.measurement_id.shape == (n_meas,)
|
|
202
|
+
assert vec.normalized_residual.shape == vec.omega_ratio.shape == (n_meas,)
|
|
203
|
+
assert len(set(vec.measurement_id.tolist())) == n_meas
|
|
204
|
+
|
|
205
|
+
rn_by_id = dict(zip(vec.measurement_id.tolist(), vec.normalized_residual.tolist(), strict=True))
|
|
206
|
+
assert len(res.worst_residuals) == 2
|
|
207
|
+
for row in res.worst_residuals:
|
|
208
|
+
assert rn_by_id[row.measurement_id] == row.normalized_residual
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_normalized_residuals_vector_pseudo_outside_scope_is_nan() -> None:
|
|
212
|
+
"""Under scope="real" a pseudo row stays in the vector with nan r_N."""
|
|
213
|
+
m = _with_pseudo_outlier()
|
|
214
|
+
res = estimate(m, tolerance=1e-10)
|
|
215
|
+
vec = res.normalized_residuals
|
|
216
|
+
assert vec is not None
|
|
217
|
+
ids = vec.measurement_id.tolist()
|
|
218
|
+
assert 900 in ids
|
|
219
|
+
pos = ids.index(900)
|
|
220
|
+
assert np.isnan(vec.normalized_residual[pos])
|
|
221
|
+
assert np.isnan(vec.omega_ratio[pos])
|
|
222
|
+
real = np.ones(len(ids), dtype=bool)
|
|
223
|
+
real[pos] = False
|
|
224
|
+
assert not np.isnan(vec.normalized_residual[real]).any()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|