From fa14dc9cab5dfa1deaf3bea75aa3ae42f1b5f8b7 Mon Sep 17 00:00:00 2001 From: "LAPTOP-G60CCHFV\\Hanane" Date: Sun, 12 Jul 2026 15:43:15 -0400 Subject: [PATCH] Add unitless solver tolerance option --- CHANGELOG.rst | 1 + pandapower/auxiliary.py | 4 ++ pandapower/run.py | 11 +++-- .../test/loadflow/test_solver_tolerance.py | 40 +++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 pandapower/test/loadflow/test_solver_tolerance.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 597af36e5..7d4e2c5d7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,7 @@ Change Log - [CHANGED] removed deprecated trafo support characteristics table (replaced by trafo_characteristc_table) - [ADDED] create function for trafo characteristic entries - [ADDED] converter for trafo characteristics +- [ADDED] Added ``solver_tolerance`` as a unitless power-flow solver tolerance option while keeping ``tolerance_mva`` as a backward-compatible alias. [upcoming release] - 2026-..-.. ------------------------------- diff --git a/pandapower/auxiliary.py b/pandapower/auxiliary.py index d9b83dd30..a450bc1bc 100644 --- a/pandapower/auxiliary.py +++ b/pandapower/auxiliary.py @@ -1724,6 +1724,8 @@ def _init_runpp_options( if key not in passed_parameters.keys()} kwargs.update(overrule_options) + solver_tolerance = kwargs.pop("solver_tolerance", None) + trafo3w_losses = kwargs.get("trafo3w_losses", "hv") v_debug = kwargs.get("v_debug", False) @@ -1854,6 +1856,8 @@ def _init_runpp_options( consider_line_temperature=consider_line_temperature, distributed_slack=distributed_slack, tdpf=tdpf, tdpf_update_r_theta=tdpf_update_r_theta, tdpf_delay_s=tdpf_delay_s) + if solver_tolerance is not None: + tolerance_mva = solver_tolerance _add_pf_options(net, tolerance_mva=tolerance_mva, trafo_loading=trafo_loading, numba=numba, ac=ac, algorithm=algorithm, max_iteration=max_iteration, v_debug=v_debug, only_v_results=only_v_results, use_umfpack=use_umfpack, diff --git a/pandapower/run.py b/pandapower/run.py index c9d7896cc..e56270162 100644 --- a/pandapower/run.py +++ b/pandapower/run.py @@ -35,14 +35,14 @@ def set_user_pf_options(net, overwrite=False, **kwargs): :param net: pandaPower network :param overwrite: specifies whether the user_pf_options is removed before setting new options - :param kwargs: load flow options, e.g. tolerance_mva = 1e-3 + :param kwargs: load flow options, e.g. solver_tolerance = 1e-3 :return: None """ standard_parameters = ['calculate_voltage_angles', 'trafo_model', 'check_connectivity', 'mode', 'copy_constraints_to_ppc', 'switch_rx_ratio', 'enforce_p_lims', 'enforce_q_lims', 'recycle', 'voltage_depend_loads', 'consider_line_temperature', 'delta', 'trafo3w_losses', 'init', 'init_vm_pu', 'init_va_degree', 'init_results', - 'tolerance_mva', 'trafo_loading', 'numba', 'ac', 'algorithm', + 'tolerance_mva', "solver_tolerance", 'trafo_loading', 'numba', 'ac', 'algorithm', 'max_iteration', 'v_debug', 'run_control', 'distributed_slack', 'lightsim2grid', 'tdpf', 'tdpf_delay_s', 'tdpf_update_r_theta'] @@ -67,7 +67,7 @@ def runpp(net, algorithm='nr', calculate_voltage_angles=True, init="auto", max_iteration="auto", tolerance_mva=1e-8, trafo_model="t", trafo_loading="current", enforce_p_lims=False, enforce_q_lims=False, check_connectivity=True, voltage_depend_loads=True, consider_line_temperature=False, - run_control=False, distributed_slack=False, tdpf=False, tdpf_delay_s=None, **kwargs): + run_control=False, distributed_slack=False, tdpf=False, tdpf_delay_s=None, solver_tolerance=None, **kwargs): """ Runs a power flow @@ -121,7 +121,8 @@ def runpp(net, algorithm='nr', calculate_voltage_angles=True, init="auto", - 30 for "nr" with "tdpf" - 40 for "helm" - tolerance_mva (float, 1e-8): loadflow termination condition referring to P / Q mismatch of node power in MVA + solver_tolerance (float, 1e-8): unitless internal solver termination tolerance for the power-flow mismatch equations. + tolerance_mva (float, 1e-8): deprecated alias for solver_tolerance. The name is kept for backward compatibility, but the value is treated as a unitless solver tolerance, not as an MVA quantity. trafo_model (str, "t"): transformer equivalent circuit model pandapower provides two equivalent circuit models for the transformer: @@ -226,6 +227,8 @@ def runpp(net, algorithm='nr', calculate_voltage_angles=True, init="auto", parameters["run_control"] = False run_control(**parameters) else: + if solver_tolerance is not None: + tolerance_mva = solver_tolerance passed_parameters = _passed_runpp_parameters(locals()) _init_runpp_options(net, algorithm=algorithm, calculate_voltage_angles=calculate_voltage_angles, diff --git a/pandapower/test/loadflow/test_solver_tolerance.py b/pandapower/test/loadflow/test_solver_tolerance.py new file mode 100644 index 000000000..832d926a6 --- /dev/null +++ b/pandapower/test/loadflow/test_solver_tolerance.py @@ -0,0 +1,40 @@ +from pandapower.create import create_bus, create_empty_network, create_ext_grid +from pandapower.run import runpp, set_user_pf_options +from math import isclose + +from pandapower.test.toolbox.test_grid_modification import net + + +def _minimal_net(): + net = create_empty_network() + bus = create_bus(net, vn_kv=20.0) + create_ext_grid(net, bus=bus) + return net + + +def test_runpp_accepts_solver_tolerance_alias(): + net = _minimal_net() + + runpp(net, solver_tolerance=1e-7, numba=False) + + assert net.converged + assert isclose(net._options["tolerance_mva"], 1e-7) + + +def test_solver_tolerance_user_pf_option(): + net = _minimal_net() + set_user_pf_options(net, solver_tolerance=1e-6) + + runpp(net, numba=False) + + assert net.converged + assert isclose(net._options["tolerance_mva"], 1e-6) + + +def test_tolerance_mva_remains_backward_compatible(): + net = _minimal_net() + + runpp(net, tolerance_mva=1e-5, numba=False) + + assert net.converged + assert isclose(net._options["tolerance_mva"], 1e-5)