Solver#

solve_power_flow(case, *, backend=None, validate=True, expand_3w_transformers=True, options=None, member_costs=None, verbose=False, **solve_opts)#

Solve power flow for a case.

This is the canonical high-level API. It handles the full pipeline: 1. Expand 3W transformers (optional) 2. Validate case against solver capabilities 3. Normalize to solver arrays (respecting build options) 4. Call backend Newton-Raphson solver 5. Extract and return results

The input case is never mutated, so the same case object can be reused across solves.

Reactive-power limits are enforced automatically whenever the case has any voltage-regulating device: generator Q limits, STATCOM / UPFC shunt current limits, and VSC mode-1 Q limits. Enforcement timing is controlled by var_limit_start_outer_iter. Widen a device's qmin/qmax in the case data if you need unconstrained behavior for a specific unit.

Parameters:
  • case -- Parsed case (from GpfCase.from_raw() or parse_raw()).

  • backend -- Backend to use: "cuda" or "cpu". Defaults to None, which auto-detects via resolve_backend (prefers "cpu", then "cuda") — the same selection the gpf CLI uses.

  • validate -- If True, validate case before solving.

  • expand_3w_transformers -- If True, expand 3W transformers via star-equivalent.

  • options -- Build options controlling which features are compiled into the network spec, used verbatim. If None, uses the case's format default (see registry.format_build_options); to customize, start from that object, edit fields, and pass it back. Use PfBuildOptions.minimal_nr() for debugging convergence issues.

  • member_costs -- Optional regulator cost override, keyed by (PF_REG_*, device_index). When given, a member's reactive sharing weight is 1/cost instead of rmpct/100, so group reactive power is split proportional to 1/cost. Members not keyed keep the rmpct/100 share.

  • verbose -- If True, print setup and solve progress to stderr: which stage is running during setup, plus a per-outer-pass trace (inner iteration count, max mismatch, and which discrete controls engaged each pass).

  • **solve_opts --

    Numerical and control knobs forwarded to the backend; any field of PfSolveOptions (max_iter, tol, q_tol, var_limit_start_outer_iter, the discrete-control gates, max_outer_iter, low_voltage_load_pu). Unknown keys raise TypeError.

    One extra key is consumed here, not forwarded: area_interchange (0 = off, default; 1 = tie lines only; 2 = tie lines and loads). When set, each area's slack generator (isw) is redispatched until the area's net interchange reaches pdes within ptol.

Returns:

SolvedCase with bus voltages, generator Q, branch flows, etc.

Raises:

Example

>>> from gpf import GpfCase, solve_power_flow
>>> case = GpfCase.from_raw("ieee39.raw")
>>> sol = solve_power_flow(case, backend="cpu")
>>> print(sol.summary())
SolvedCase(CONVERGED in 4 iterations, ...)

# Debug mode with minimal features: >>> from gpf import PfBuildOptions >>> sol = solve_power_flow(case, options=PfBuildOptions.minimal_nr())

solve_file(path, **overrides)#

Parse a case file and solve it in one call.

The case file's format is detected from its extension (.raw, .rawx/.json, .m) and the matching modeling conventions are applied automatically, so this is just parse-then-solve. Any explicit keyword wins over those defaults.

Parameters:
  • path -- Filesystem path to the case file (str or Path). The extension selects the parser; unknown extensions raise ValueError.

  • **overrides -- Keyword arguments forwarded to solve_power_flow() (e.g. backend, validate, options, or any PfSolveOptions field). Each overrides the format default.

Returns:

SolvedCase with bus voltages, generator Q, branch flows, etc.

Raises:
class SolvePreset(var_limit_start_outer_iter=0, build=<factory>)#

Bases: object

Per-format solver defaults: a plain data record, not a merge engine.

var_limit_start_outer_iter is the var-limit policy used when the caller passes no override. build is the set of PfBuildOptions field values the format implies; format_build_options materializes it into a concrete PfBuildOptions the caller can edit field-by-field and pass back.

gpf.RAW_PRESET: SolvePreset#
gpf.MATPOWER_PRESET: SolvePreset#
format_build_options(case)#

Complete, format-correct PfBuildOptions for case.

The starting point for customization: edit fields on the returned object and pass it as solve_power_flow(case, options=...). Equivalent to what solve_power_flow uses by default when options is omitted.

parse_var_limit_mode(text)#

Translate a user-facing mode string into the backend integer.

Accepts:

"off" -> PF_VAR_LIMIT_OFF (-1) "immediate" -> PF_VAR_LIMIT_IMMEDIATE (0) "auto" -> PF_VAR_LIMIT_AUTO (1) "at:<K>" -> K (any non-negative integer; advanced)

Any other string raises ValueError. Case-insensitive.

gpf.PF_VAR_LIMIT_OFF: int#
gpf.PF_VAR_LIMIT_IMMEDIATE: int#
gpf.PF_VAR_LIMIT_AUTO: int#
class SolvedCase(sbase, basfrq, bus_ids, vm, va, p_inj, q_inj, bus_types_final, gen_bus_ids, gen_machids, gen_p, gen_q, branch_from_bus_ids, branch_to_bus_ids, branch_ckts, p_from, q_from, p_to, q_to, p_loss, q_loss, vsc_dc_names, vsc_dc_bus1_ids, vsc_dc_bus2_ids, vsc_dc_p_conv1, vsc_dc_q_conv1, vsc_dc_p_conv2, vsc_dc_q_conv2, vsc_dc_i_dc, vsc_dc_p_loss, vsc_dc_v_dc1, vsc_dc_v_dc2, converged, iterations, outer_iterations, max_mismatch, backend, solve_time_s=0.0, parse_time_s=0.0, warnings=(), iteration_history=(), exit_reason=PfExitReason.CONVERGED, gen_limit_binding=<factory>, statcom_limit_binding=<factory>, upfc_shunt_limit_binding=<factory>, vsc_limit_binding=<factory>, lcc_dc_names=<factory>, lcc_dc_rect_bus_ids=<factory>, lcc_dc_inv_bus_ids=<factory>, lcc_dc_p_rect=<factory>, lcc_dc_q_rect=<factory>, lcc_dc_p_inv=<factory>, lcc_dc_q_inv=<factory>, lcc_dc_i_d_pu=<factory>, lcc_dc_cos_alpha=<factory>, lcc_dc_cos_gamma=<factory>, lcc_dc_tap_r=<factory>, lcc_dc_tap_i=<factory>, lcc_dc_mode=<factory>, lcc_dc_limit_flags=<factory>, jacobian_dim=0, n_reg_groups=0, n_reg_groups_multi=0, n_reg_members=0, branch_rates=<factory>, rating_names=<factory>)#

Bases: object

Immutable power flow solution.

All arrays are in per-unit on system base (sbase). Angles are in radians.

property any_limit_binding#

True if at least one regulator of any kind hit its limit.

property augmented_dim#

Voltage-regulation rows above the base system; equals n_reg_members + n_reg_groups_multi. Zero without regulation.

property base_dim#

Base power-flow Newton dimension, always 2 * n_bus.

get_bus_voltage(bus_id)#

Get voltage at a bus.

Parameters:

bus_id -- bus number.

Returns:

Voltage magnitude (pu) and angle (radians).

Return type:

(vm_pu, va_rad)

Raises:

KeyError -- If bus not found.

get_generator_q(bus_id, machid='1')#

Get generator reactive power output.

Parameters:
  • bus_id -- bus number.

  • machid -- Machine ID (default "1").

Returns:

Q output in pu on system base.

Raises:

KeyError -- If generator not found.

property n_limit_binding#

Total regulator-kind devices whose VAR/Q/current limit bound during the last solve (generator + STATCOM + UPFC-shunt + VSC).

property n_reg_groups_reduced#

a q_m column but no lambda.

Type:

Single-member (reduced-form) groups

property status#

Return convergence status as string.

summary()#

Return a brief summary of the solution.

to_dict()#

Convert to dictionary (arrays become lists).

to_report(case_name='')#

Format as plain text report.

For rich terminal output or HTML, use the public render helper:

from gpf import render print(render(solved_case)) # Auto-detects best format

PfIterationRecord#

alias of IterationRecord

PfArgmaxResults#

alias of ArgmaxResults

PfArgmaxBin#

alias of ArgmaxBin

class UnsupportedPowerFlowCaseError#

Bases: ValueError

Raised when a case contains features not supported by the solver.