gridstate 2.5.0__tar.gz → 2.6.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.
Files changed (227) hide show
  1. {gridstate-2.5.0 → gridstate-2.6.0}/CHANGELOG.md +18 -0
  2. {gridstate-2.5.0 → gridstate-2.6.0}/PKG-INFO +1 -1
  3. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/_version.py +3 -3
  4. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/api.py +5 -6
  5. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/ipm_hints.py +1 -1
  6. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/config.py +32 -0
  7. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/passes.py +3 -0
  8. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/ipm_setup.py +55 -10
  9. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/PKG-INFO +1 -1
  10. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/scm_version.json +2 -2
  11. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_balance_modes.py +67 -0
  12. {gridstate-2.5.0 → gridstate-2.6.0}/.github/workflows/ci.yml +0 -0
  13. {gridstate-2.5.0 → gridstate-2.6.0}/.github/workflows/release.yml +0 -0
  14. {gridstate-2.5.0 → gridstate-2.6.0}/.gitignore +0 -0
  15. {gridstate-2.5.0 → gridstate-2.6.0}/.pre-commit-config.yaml +0 -0
  16. {gridstate-2.5.0 → gridstate-2.6.0}/LICENSE +0 -0
  17. {gridstate-2.5.0 → gridstate-2.6.0}/Makefile +0 -0
  18. {gridstate-2.5.0 → gridstate-2.6.0}/README.md +0 -0
  19. {gridstate-2.5.0 → gridstate-2.6.0}/build_cython.py +0 -0
  20. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__init__.py +0 -0
  21. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__pyinstaller/__init__.py +0 -0
  22. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__pyinstaller/hook-gridstate.py +0 -0
  23. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/_arrays.py +0 -0
  24. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/adapters/__init__.py +0 -0
  25. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/adapters/from_pandapower.py +0 -0
  26. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/__init__.py +0 -0
  27. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/_selinv_kernels.py +0 -0
  28. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/base.py +0 -0
  29. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/estimators.py +0 -0
  30. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/jacobian_pattern.py +0 -0
  31. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/normalized_residuals.py +0 -0
  32. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/__init__.py +0 -0
  33. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/_gram_numba.py +0 -0
  34. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/ipm.py +0 -0
  35. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/ipm_pd.py +0 -0
  36. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/kkt_solver.py +0 -0
  37. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/status.py +0 -0
  38. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/wls.py +0 -0
  39. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/bad_data_repass.py +0 -0
  40. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/bounds.py +0 -0
  41. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/constants.py +0 -0
  42. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/__init__.py +0 -0
  43. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/_legacy.py +0 -0
  44. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/containers.py +0 -0
  45. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/derived.py +0 -0
  46. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/derived_tables.py +0 -0
  47. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/serialize.py +0 -0
  48. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/tables.py +0 -0
  49. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/validate.py +0 -0
  50. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/version.py +0 -0
  51. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/load_characteristics.py +0 -0
  52. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/losses.py +0 -0
  53. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/measurement_ids.py +0 -0
  54. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/__init__.py +0 -0
  55. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/context.py +0 -0
  56. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/manifest.py +0 -0
  57. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/orchestration.py +0 -0
  58. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/preparation.py +0 -0
  59. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/runner.py +0 -0
  60. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/steps.py +0 -0
  61. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/post_processing.py +0 -0
  62. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/__init__.py +0 -0
  63. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/_scan.py +0 -0
  64. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/meas_rows.py +0 -0
  65. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/mirror_voltage.py +0 -0
  66. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/node_props.py +0 -0
  67. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/pseudo_measurements.py +0 -0
  68. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/py.typed +0 -0
  69. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/quality_summary.py +0 -0
  70. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/resolve_pass.py +0 -0
  71. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/result.py +0 -0
  72. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/runtime.py +0 -0
  73. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/shunt_sanity.py +0 -0
  74. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/solution_hints.py +0 -0
  75. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/state.py +0 -0
  76. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/__init__.py +0 -0
  77. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/_filters.py +0 -0
  78. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/apply_resolved.py +0 -0
  79. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/generators.py +0 -0
  80. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/kinds.py +0 -0
  81. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/load_only_injection.py +0 -0
  82. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/loss_filter.py +0 -0
  83. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/measurements.py +0 -0
  84. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/noise.py +0 -0
  85. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/on_line.py +0 -0
  86. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/quality.py +0 -0
  87. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/rpn.py +0 -0
  88. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/shunts.py +0 -0
  89. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/sigma_floor.py +0 -0
  90. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/units.py +0 -0
  91. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/voltage_filter.py +0 -0
  92. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/voltage_nominal.py +0 -0
  93. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/topology.py +0 -0
  94. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/units.py +0 -0
  95. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/utils.py +0 -0
  96. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/v_mirror.py +0 -0
  97. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/v_refine.py +0 -0
  98. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/__init__.py +0 -0
  99. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/_diagnostics.py +0 -0
  100. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/bad_data.py +0 -0
  101. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/chi2_test.py +0 -0
  102. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/observability.py +0 -0
  103. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/working.py +0 -0
  104. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/ybus.py +0 -0
  105. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/z_vector.py +0 -0
  106. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/SOURCES.txt +0 -0
  107. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/dependency_links.txt +0 -0
  108. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/entry_points.txt +0 -0
  109. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/requires.txt +0 -0
  110. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/scm_file_list.json +0 -0
  111. {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/top_level.txt +0 -0
  112. {gridstate-2.5.0 → gridstate-2.6.0}/pyproject.toml +0 -0
  113. {gridstate-2.5.0 → gridstate-2.6.0}/setup.cfg +0 -0
  114. {gridstate-2.5.0 → gridstate-2.6.0}/tests/__init__.py +0 -0
  115. {gridstate-2.5.0 → gridstate-2.6.0}/tests/_golden.py +0 -0
  116. {gridstate-2.5.0 → gridstate-2.6.0}/tests/conftest.py +0 -0
  117. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_adapters_lazy_import.py +0 -0
  118. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_aggregate_generators.py +0 -0
  119. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_algebra_base.py +0 -0
  120. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_anti_overshoot.py +0 -0
  121. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_arrays_helpers.py +0 -0
  122. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bad_data.py +0 -0
  123. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bad_data_repass.py +0 -0
  124. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bounds.py +0 -0
  125. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_boxed_balance.py +0 -0
  126. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_breaker_reactance.py +0 -0
  127. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_chain_mirror.py +0 -0
  128. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract.py +0 -0
  129. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract_edge_cases.py +0 -0
  130. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract_runtime.py +0 -0
  131. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118.json +0 -0
  132. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118.npz +0 -0
  133. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118_degraded.json +0 -0
  134. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118_degraded.npz +0 -0
  135. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14.json +0 -0
  136. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14.npz +0 -0
  137. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14_degraded.json +0 -0
  138. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14_degraded.npz +0 -0
  139. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30.json +0 -0
  140. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30.npz +0 -0
  141. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30_degraded.json +0 -0
  142. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30_degraded.npz +0 -0
  143. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/manifest.json +0 -0
  144. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case118.npz +0 -0
  145. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case118_truth.npz +0 -0
  146. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case14.npz +0 -0
  147. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case14_truth.npz +0 -0
  148. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case30.npz +0 -0
  149. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case30_truth.npz +0 -0
  150. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_derived_tables.py +0 -0
  151. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_enum_codes.py +0 -0
  152. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_flow_sigma_floor.py +0 -0
  153. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_from_pandapower.py +0 -0
  154. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_generator_shunt_kernels.py +0 -0
  155. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_golden.py +0 -0
  156. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_gram_numba.py +0 -0
  157. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ieee_cases.py +0 -0
  158. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm.py +0 -0
  159. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_hints.py +0 -0
  160. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_injection_roles.py +0 -0
  161. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_integration.py +0 -0
  162. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_pd.py +0 -0
  163. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_jacobian_pattern.py +0 -0
  164. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_kkt_solver.py +0 -0
  165. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_load_characteristic_segments.py +0 -0
  166. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_load_only_injection.py +0 -0
  167. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_breakdown.py +0 -0
  168. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_q_convention.py +0 -0
  169. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_trafo_classification.py +0 -0
  170. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_materialize_kernel.py +0 -0
  171. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_measurement_filter_kernels.py +0 -0
  172. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_measurement_ids.py +0 -0
  173. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_mirror_voltage_kernel.py +0 -0
  174. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_near_critical_ranking.py +0 -0
  175. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_neutral_wording.py +0 -0
  176. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_noise_model.py +0 -0
  177. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_normalized_residuals.py +0 -0
  178. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_numpy_only_runtime.py +0 -0
  179. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_observability.py +0 -0
  180. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_on_line_kernel.py +0 -0
  181. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_perf_synthetic_network.py +0 -0
  182. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline.py +0 -0
  183. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_config_validation.py +0 -0
  184. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_idempotent.py +0 -0
  185. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_invariant_errors.py +0 -0
  186. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_step_order.py +0 -0
  187. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_warm_start.py +0 -0
  188. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_working_layer.py +0 -0
  189. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_post_processing.py +0 -0
  190. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_preparation_steps.py +0 -0
  191. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_prepare_network.py +0 -0
  192. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pseudo_unknown_load.py +0 -0
  193. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pseudo_v_unobservable.py +0 -0
  194. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_quality_summary_paths.py +0 -0
  195. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_reconcile_balance.py +0 -0
  196. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_refine_merge.py +0 -0
  197. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_resolve_pass.py +0 -0
  198. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_result_quality_summary.py +0 -0
  199. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_rn_selected_inversion.py +0 -0
  200. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_serialize_npz.py +0 -0
  201. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_shunt_sanity.py +0 -0
  202. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_solution_hints.py +0 -0
  203. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_solve_status.py +0 -0
  204. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_state.py +0 -0
  205. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_state_range.py +0 -0
  206. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_apply_kernel.py +0 -0
  207. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_bounds.py +0 -0
  208. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_physics_kernels.py +0 -0
  209. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_tm_code_quality.py +0 -0
  210. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_topology_kernels.py +0 -0
  211. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_topology_port.py +0 -0
  212. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_transformer_from_shunt.py +0 -0
  213. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_units.py +0 -0
  214. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_units_array_kernels.py +0 -0
  215. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_v_mirror.py +0 -0
  216. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_v_refine.py +0 -0
  217. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_variance_charging.py +0 -0
  218. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_version.py +0 -0
  219. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_voltage_calibration_gen_nodes.py +0 -0
  220. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_voltage_range_filter_fallback.py +0 -0
  221. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_wls.py +0 -0
  222. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_wls_robustness.py +0 -0
  223. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_working_container.py +0 -0
  224. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ybus.py +0 -0
  225. {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_z_vector.py +0 -0
  226. {gridstate-2.5.0 → gridstate-2.6.0}/tools/gen_ieee_fixtures.py +0 -0
  227. {gridstate-2.5.0 → gridstate-2.6.0}/tools/golden.py +0 -0
@@ -9,6 +9,24 @@ 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.6.0 (2026-10-18)
13
+
14
+ ### Behavior changes
15
+
16
+ - `ipm_pd` gets the 300-iteration budget with equality rows too (it was 100
17
+ before the primal fallback), including the global `ipm_balance_mode="hard"`:
18
+ with the adaptive box damping and the measurement-space stopping test of
19
+ v2.4.1 the long budget converges where the short one fell back.
20
+
21
+ ### Feat
22
+
23
+ - `ipm_transit_balance_mode` (new, default `soft`): `hard` makes the P and Q
24
+ balance rows of transit nodes (no `exist_gen` / `exist_load`) equality
25
+ constraints of the solver, to `ipm_transit_balance_tol_p_mw` (new, default
26
+ 0.01) / `ipm_transit_balance_tol_q_mvar` (new, default 0.1); the other
27
+ balance rows stay soft. The global hard balance overrides it. `IPMSetup`
28
+ gains `eq_rows` / `eq_tol`.
29
+
12
30
  ## v2.5.0 (2026-10-18)
13
31
 
14
32
  ### Behavior changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gridstate
3
- Version: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: Power system State Estimation: pure-Python WLS/IPM on numpy/scipy, input via a versioned file contract (npz).
5
5
  Author-email: Evgeny Istomin <gena@alpisto.eu>
6
6
  License: MIT
@@ -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.5.0'
22
- __version_tuple__ = version_tuple = (2, 5, 0)
21
+ __version__ = version = '2.6.0'
22
+ __version_tuple__ = version_tuple = (2, 6, 0)
23
23
 
24
- __commit_id__ = commit_id = 'g98bb957af'
24
+ __commit_id__ = commit_id = 'ge81a73f8f'
@@ -826,7 +826,7 @@ def _run_ipm(
826
826
  delta, v, _pg, _qg, _pn, _qn = unpack_full(x, layout_ipm)
827
827
  return algebra.evaluate_jacobian(v, delta)
828
828
 
829
- eq_idx = setup.balance_rows if setup.balance_tol is not None else None
829
+ eq_idx = setup.eq_rows
830
830
  pd_result: IPMResult | None = None
831
831
  if solver == "ipm_pd":
832
832
  mb_rows = mb_lo = mb_hi = None
@@ -852,13 +852,12 @@ def _run_ipm(
852
852
  meas_box_lo=mb_lo,
853
853
  meas_box_hi=mb_hi,
854
854
  eq_idx=eq_idx,
855
- eq_tol=setup.balance_tol,
855
+ eq_tol=setup.eq_tol,
856
856
  mu_init=1.0,
857
857
  step_tol=max(tolerance, 1e-4),
858
858
  # Weakly determined units need up to ~260 iterations with separate
859
- # injection parts; a hard balance does not converge in that budget
860
- # either way, so it keeps the short one before the fallback.
861
- max_iter=max(max_iterations, 100 if eq_idx is not None else 300),
859
+ # injection parts, with or without equality rows.
860
+ max_iter=max(max_iterations, 300),
862
861
  tr_radius=0.5,
863
862
  huber_c=huber_c,
864
863
  huber_mask=huber_mask,
@@ -910,7 +909,7 @@ def _run_ipm(
910
909
  huber_adaptive_k=2.0,
911
910
  kkt_solver=kkt,
912
911
  eq_idx=eq_idx,
913
- eq_tol=setup.balance_tol,
912
+ eq_tol=setup.eq_tol,
914
913
  )
915
914
  if solver == "ipm_pd":
916
915
  result.message = f"ipm_pd fallback to ipm ({pd_message}): {result.message}"
@@ -219,7 +219,7 @@ def ipm_convergence_hints(
219
219
  meas_index=setup.meas_index,
220
220
  network_pu=network_pu,
221
221
  # Equality rows: their σ is a penalty, not a measurement error.
222
- skip=setup.balance_rows if setup.balance_tol is not None else None,
222
+ skip=setup.eq_rows,
223
223
  part_rows=setup.role_rows,
224
224
  top=top,
225
225
  )
@@ -610,6 +610,38 @@ class PipelineConfig:
610
610
  "median(σ²_data) / factor. Their injection is known to be zero; a loose balance "
611
611
  "turns data conflicts into a fictitious injection. 0 — off.",
612
612
  )
613
+ ipm_transit_balance_mode: str = _param(
614
+ "soft",
615
+ group=_G_IPM,
616
+ label="Balance mode of transit nodes",
617
+ control="select",
618
+ choices=["soft", "hard"],
619
+ depends={"algorithm": "ipm"},
620
+ help="soft — the balance of a transit node (no exist_gen/exist_load) is a "
621
+ "weighted row like the others (ipm_transit_balance_weight_factor); hard — an "
622
+ "equality constraint to ipm_transit_balance_tol_p_mw / _q_mvar, the other "
623
+ "balance rows stay soft. No effect when ipm_balance_mode=hard.",
624
+ )
625
+ ipm_transit_balance_tol_p_mw: float = _param(
626
+ 0.01,
627
+ group=_G_IPM,
628
+ label="Transit balance tolerance P, MW",
629
+ control="number",
630
+ min=1e-6,
631
+ max=1e3,
632
+ depends={"ipm_transit_balance_mode": "hard"},
633
+ help="Admissible |P injection| of a transit node under the hard transit balance.",
634
+ )
635
+ ipm_transit_balance_tol_q_mvar: float = _param(
636
+ 0.1,
637
+ group=_G_IPM,
638
+ label="Transit balance tolerance Q, MVAr",
639
+ control="number",
640
+ min=1e-6,
641
+ max=1e3,
642
+ depends={"ipm_transit_balance_mode": "hard"},
643
+ help="Admissible |Q injection| of a transit node under the hard transit balance.",
644
+ )
613
645
  ipm_prior_sigma2_bus_equiv_pu: float = _param(
614
646
  0.01,
615
647
  group=_G_IPM,
@@ -52,6 +52,9 @@ def _ipm_kwargs(cfg: PipelineConfig) -> dict:
52
52
  "prior_sigma2_bus_equiv_pu": cfg.ipm_prior_sigma2_bus_equiv_pu,
53
53
  "boxed_balance_weight_factor": cfg.ipm_boxed_balance_weight_factor,
54
54
  "transit_balance_weight_factor": cfg.ipm_transit_balance_weight_factor,
55
+ "transit_balance_mode": cfg.ipm_transit_balance_mode,
56
+ "transit_balance_tol_p_mw": cfg.ipm_transit_balance_tol_p_mw,
57
+ "transit_balance_tol_q_mvar": cfg.ipm_transit_balance_tol_q_mvar,
55
58
  "trust_region_scope": cfg.ipm_trust_region_scope,
56
59
  "balance_mode": cfg.ipm_balance_mode,
57
60
  "balance_tol_p_mw": cfg.ipm_balance_tol_p_mw,
@@ -282,6 +282,11 @@ class IPMSetup:
282
282
  # ``balance_tol`` holds the admissible |imbalance| per balance row in p.u.
283
283
  # ``None`` in the soft mode.
284
284
  balance_tol: np.ndarray | None = None
285
+ # Rows the solver enforces as equalities and their admissible |c| (p.u.):
286
+ # every balance row in the hard mode, the transit balance rows with
287
+ # ``transit_balance_mode="hard"``; ``None`` — no equality rows.
288
+ eq_rows: np.ndarray | None = None
289
+ eq_tol: np.ndarray | None = None
285
290
  # ``injection_roles``: rows of ``z`` that measure a box variable directly
286
291
  # (a generation / load part of a node injection) and their measurement ids;
287
292
  # ``role_dropped_ids`` — part rows folded back into a net injection row.
@@ -556,6 +561,9 @@ def build_ipm_setup(
556
561
  hard_balance_rho_factor: float = 1e3,
557
562
  balance_tol_p_mw: float = 1.0,
558
563
  balance_tol_q_mvar: float = 10.0,
564
+ transit_balance_mode: str = "soft",
565
+ transit_balance_tol_p_mw: float = 0.01,
566
+ transit_balance_tol_q_mvar: float = 0.1,
559
567
  fixed_injection_from_input: bool = False,
560
568
  injection_roles: bool = False,
561
569
  measurements: _ArrayCollection | None = None,
@@ -628,6 +636,14 @@ def build_ipm_setup(
628
636
  hard_balance_rho_factor: see ``balance_mode``.
629
637
  balance_tol_p_mw, balance_tol_q_mvar: admissible |imbalance| of a hard
630
638
  P / Q balance row (MW / MVAr).
639
+ transit_balance_mode: ``"soft"`` (default) — the balance rows of transit
640
+ nodes (no ``exist_gen`` / ``exist_load``) are weighted like the
641
+ others (see ``transit_balance_weight_factor``); ``"hard"`` — they are
642
+ equality constraints with the penalty of ``balance_mode="hard"``,
643
+ the other balance rows stay soft. Ignored when ``balance_mode`` is
644
+ already ``"hard"``.
645
+ transit_balance_tol_p_mw, transit_balance_tol_q_mvar: admissible
646
+ |injection| of a transit node in the hard transit mode (MW / MVAr).
631
647
  fixed_injection_from_input: the balance row of a node carries the
632
648
  input injection of its parts without a box variable (no
633
649
  ``exist_gen`` / ``exist_load``) as a fixed term instead of zero.
@@ -732,6 +748,11 @@ def build_ipm_setup(
732
748
  if balance_mode not in ("soft", "hard"):
733
749
  raise ValueError(f"balance_mode={balance_mode!r} is not one of ['soft', 'hard']")
734
750
  hard = balance_mode == "hard"
751
+ if transit_balance_mode not in ("soft", "hard"):
752
+ raise ValueError(
753
+ f"transit_balance_mode={transit_balance_mode!r} is not one of ['soft', 'hard']"
754
+ )
755
+ transit_hard = transit_balance_mode == "hard" and not hard and n_balance > 0
735
756
 
736
757
  # ---- Prior measurements: z=0, individual σ². Only for box-vars with σ²>0 ----
737
758
  pgen_prior_arr = np.asarray(pgen_sec.prior_s2, dtype=np.float64)
@@ -816,6 +837,12 @@ def build_ipm_setup(
816
837
  for start in (n_old, n_old + n_balance):
817
838
  rows = sigma2_new[start : start + n_balance]
818
839
  rows[transit] = np.minimum(rows[transit], transit_s2)
840
+ transit_eq = np.zeros(0, dtype=np.int64)
841
+ if transit_hard:
842
+ transit = _transit_mask(nodes_arr, active_ids)
843
+ pos = np.flatnonzero(transit)
844
+ transit_eq = np.concatenate([n_old + pos, n_old + n_balance + pos]).astype(np.int64)
845
+ sigma2_new[transit_eq] = _adaptive_balance_sigma2(sigma2_old, hard_balance_rho_factor)
819
846
  if n_prior > 0:
820
847
  prior_sigmas = np.concatenate(
821
848
  [
@@ -893,6 +920,31 @@ def build_ipm_setup(
893
920
  meas_id=new_meas_id,
894
921
  )
895
922
 
923
+ balance_tol = (
924
+ np.concatenate(
925
+ [
926
+ np.full(n_balance, balance_tol_p_mw / BASE_MVA),
927
+ np.full(n_balance, balance_tol_q_mvar / BASE_MVA),
928
+ ]
929
+ )
930
+ if hard
931
+ else None
932
+ )
933
+ eq_rows: np.ndarray | None = None
934
+ eq_tol: np.ndarray | None = None
935
+ if hard:
936
+ eq_rows = np.arange(n_old, n_old + 2 * n_balance, dtype=np.int64)
937
+ eq_tol = balance_tol
938
+ elif transit_eq.size:
939
+ n_t = transit_eq.size // 2
940
+ eq_rows = transit_eq
941
+ eq_tol = np.concatenate(
942
+ [
943
+ np.full(n_t, transit_balance_tol_p_mw / BASE_MVA),
944
+ np.full(n_t, transit_balance_tol_q_mvar / BASE_MVA),
945
+ ]
946
+ )
947
+
896
948
  return IPMSetup(
897
949
  layout=layout,
898
950
  box_idx_in_state=box_idx_arr,
@@ -907,16 +959,9 @@ def build_ipm_setup(
907
959
  meas_index=meas_index_aug,
908
960
  balance_start=n_old,
909
961
  n_balance=n_balance,
910
- balance_tol=(
911
- np.concatenate(
912
- [
913
- np.full(n_balance, balance_tol_p_mw / BASE_MVA),
914
- np.full(n_balance, balance_tol_q_mvar / BASE_MVA),
915
- ]
916
- )
917
- if hard
918
- else None
919
- ),
962
+ balance_tol=balance_tol,
963
+ eq_rows=eq_rows,
964
+ eq_tol=eq_tol,
920
965
  role_rows=np.arange(role_start, n_new, dtype=np.int64),
921
966
  role_meas_ids=role_ids.astype(np.int64),
922
967
  role_dropped_ids=np.asarray(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gridstate
3
- Version: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: Power system State Estimation: pure-Python WLS/IPM on numpy/scipy, input via a versioned file contract (npz).
5
5
  Author-email: Evgeny Istomin <gena@alpisto.eu>
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "2.5.0",
2
+ "tag": "2.6.0",
3
3
  "distance": 0,
4
- "node": "g98bb957af8b143153db7f269753619ec87bf6f6e",
4
+ "node": "ge81a73f8f85db175e6e502a935ee299b48796dc5",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-10-18"
@@ -75,6 +75,52 @@ def test_unknown_balance_mode_is_rejected():
75
75
  _setup(_build_net_with_transit(), balance_mode="strict")
76
76
 
77
77
 
78
+ def test_transit_hard_mode_makes_only_transit_rows_equalities():
79
+ # Node order 1..4: node 2 is the transit node.
80
+ setup = _setup(
81
+ _build_net_with_transit(),
82
+ transit_balance_mode="hard",
83
+ transit_balance_tol_p_mw=0.02,
84
+ transit_balance_tol_q_mvar=0.2,
85
+ hard_balance_rho_factor=1e3,
86
+ )
87
+ assert setup.balance_tol is None
88
+ assert setup.eq_rows is not None and setup.eq_tol is not None
89
+ np.testing.assert_array_equal(setup.eq_rows, [2 + 1, 2 + N_BALANCE + 1])
90
+ np.testing.assert_allclose(setup.eq_tol, [0.02 / BASE_MVA, 0.2 / BASE_MVA])
91
+ sigma2 = setup.r_matrix.diagonal()[2 : 2 + 2 * N_BALANCE]
92
+ soft = _setup(_build_net_with_transit()).r_matrix.diagonal()[2 : 2 + 2 * N_BALANCE]
93
+ is_eq = np.zeros(2 * N_BALANCE, dtype=bool)
94
+ is_eq[[1, N_BALANCE + 1]] = True
95
+ assert np.allclose(sigma2[is_eq], 2.5e-4 / 1e3)
96
+ np.testing.assert_array_equal(sigma2[~is_eq], soft[~is_eq])
97
+
98
+
99
+ def test_soft_modes_have_no_equality_rows():
100
+ setup = _setup(_build_net_with_transit(), transit_balance_weight_factor=10.0)
101
+ assert setup.eq_rows is None and setup.eq_tol is None
102
+
103
+
104
+ def test_global_hard_mode_overrides_the_transit_mode():
105
+ setup = _setup(
106
+ _build_net_with_transit(),
107
+ balance_mode="hard",
108
+ balance_tol_p_mw=2.0,
109
+ transit_balance_mode="hard",
110
+ transit_balance_tol_p_mw=0.02,
111
+ )
112
+ assert setup.eq_rows is not None and setup.eq_tol is not None
113
+ np.testing.assert_array_equal(setup.eq_rows, setup.balance_rows)
114
+ np.testing.assert_array_equal(setup.eq_tol, setup.balance_tol)
115
+
116
+
117
+ def test_unknown_transit_balance_mode_is_rejected():
118
+ with pytest.raises(ValueError, match="transit_balance_mode"):
119
+ _setup(_build_net_with_transit(), transit_balance_mode="strict")
120
+ with pytest.raises(ValueError, match="ipm_transit_balance_mode"):
121
+ PipelineConfig(algorithm="ipm_pd", ipm_transit_balance_mode="strict")
122
+
123
+
78
124
  def test_fixed_injection_from_input():
79
125
  m = _build_net_with_transit()
80
126
  # Transit node 2 gets a non-estimated load and generation.
@@ -131,6 +177,26 @@ def test_hard_balance_closes_the_estimated_imbalance(algorithm: str):
131
177
  assert imb_p <= 0.1 and imb_q <= 0.1
132
178
 
133
179
 
180
+ @pytest.mark.parametrize("algorithm", ["ipm", "ipm_pd"])
181
+ def test_transit_hard_balance_zeroes_the_transit_injection(algorithm: str):
182
+ # Soft, the transit node 2 absorbs the data conflict (≈ 4 MW / 14 MVAr).
183
+ soft = _build_net_with_transit()
184
+ estimate(soft, algorithm=algorithm, reconcile_balance=False, include_quality_summary=False)
185
+ n_soft = soft.nodes.to_numpy()
186
+ assert abs(n_soft["p_inj_calc"][1]) > 1.0 and abs(n_soft["q_inj_calc"][1]) > 1.0
187
+ m = _build_net_with_transit()
188
+ res = estimate(
189
+ m,
190
+ algorithm=algorithm,
191
+ reconcile_balance=False,
192
+ include_quality_summary=False,
193
+ transit_balance_mode="hard",
194
+ )
195
+ assert res.success
196
+ n = m.nodes.to_numpy()
197
+ assert abs(n["p_inj_calc"][1]) <= 0.01 and abs(n["q_inj_calc"][1]) <= 0.1
198
+
199
+
134
200
  def test_ipm_pd_close_to_ipm():
135
201
  results = {}
136
202
  for algorithm in ("ipm", "ipm_pd"):
@@ -170,6 +236,7 @@ def test_measurement_bounds_require_ipm_pd():
170
236
  def test_config_defaults_and_ranges():
171
237
  cfg = PipelineConfig(algorithm="ipm_pd")
172
238
  assert cfg.ipm_balance_mode == "soft"
239
+ assert cfg.ipm_transit_balance_mode == "soft"
173
240
  assert not cfg.ipm_measurement_bounds and not cfg.ipm_fixed_injection_from_input
174
241
  # The soft balance weight may now exceed the median measurement weight tenfold.
175
242
  dataclasses.replace(cfg, ipm_balance_weight_factor=1e3)
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