ACPFlow Runner Reference
Public API
Sparlectra.run_acpflow — Method
run_acpflow(; net=nothing, casefile=nothing, path=nothing, config=nothing, performance_profile=nothing) -> SparlectraRunResultCompatibility alias for run_sparlectra.
This function uses the same configuration-driven framework workflow as run_sparlectra. It does not support the former keyword-heavy runner API. Solver, import, output, Q-limit, start-mode, and diagnostic behavior must be configured through SparlectraConfig or YAML.
Sparlectra.run_sparlectra — Method
run_sparlectra(; net=nothing, casefile=nothing, path=nothing, config=nothing, performance_profile=nothing) -> SparlectraRunResultRun the configuration-driven Sparlectra framework workflow. Pass exactly one of net or casefile. File-based runs import a MATPOWER case using config.matpower; in-memory runs solve the supplied network directly. Solver, control-loop, and output behavior are taken from one SparlectraConfig.
Sparlectra.run_sparlectra_cases — Method
run_sparlectra_cases(; config=nothing, path=nothing, performance_profile=nothing) -> Vector{SparlectraRunResult}Run configured MATPOWER cases sequentially in deterministic order. A non-empty config.runtime.cases list takes precedence over config.runtime.case. Bare case names are resolved through ensure_casefile, which downloads standard MATPOWER cases on demand. Batch-level performance-profile aggregation is not supported; profile individual run_sparlectra calls instead.
Sparlectra.build_pos_map — Method
build_pos_map(non_slack, n) -> pos::Vector{Int}pos[i]=k, wenn i==non_slack[k], sonst 0.
Sparlectra.build_qload_pu — Method
build_qload_pu(net) -> Qload_pu::Vector{Float64}Aggregated reactive load per bus in p.u. (sum of non-generator prosmps qVal / baseMVA).
Sparlectra.build_voltage_vector — Method
build_voltage_vector(busVec) -> V::Vector{ComplexF64}Sparlectra.calc_currents — Method
calc_currents(Y, V) -> ICompute bus current injections I = Y * V.
Sparlectra.calc_injections — Method
calc_injections(Y, V) -> SCompute complex bus power injections S = V .* conj(Y*V).
Sparlectra.compute_sbus_and_totals — Method
compute_sbus_and_totals(Y, V, baseMVA) -> (Sbus_pu, p_MW, q_MVar)Sparlectra.extract_bus_types_and_vset — Method
extract_bus_types_and_vset(net) -> (bus_types::Vector{Symbol}, Vset::Vector{Float64}, slack_idx::Int)bus_types uses :Slack/:PV/:PQ, Vset is vm setpoint (PV) or current vm default.
Sparlectra.slack_elimination_indices — Method
slack_elimination_indices(n, slack_idx)Return (nonslack, rowidx, col_idx) for [P;Q] and [Vr;Vi] layout of size 2n.
Sparlectra.solve_linear — Method
solve_linear(A, b; allow_pinv=true, svd_max_n=DEFAULT_DENSE_FALLBACK_MAX_N)Solve A*x = b. Sparse matrices are handled by solve_sparse_system and are never converted to dense storage. Dense callers may still use the small-system SVD fallback when explicitly allowed; svd_max_n bounds the system size the SVD fallback accepts. Callers for whom rank deficiency is an EXPECTED state rather than a hard fault (the WLS normal equations of the state estimation, where released extra states can turn out collectively dependent) raise the bound so a singular system degrades to a least-squares step instead of an exception; the power-flow callers keep the small default on purpose.
Sparlectra.solve_sparse_system — Method
solve_sparse_system(A::SparseMatrixCSC, b; context=:powerflow, diagnostics=nothing) -> VectorSolve the sparse linear system A*x = b. The primary path is the standard sparse solve A \ b (UMFPACK LU for a general square matrix), with sparse QR as the fallback for a singular matrix. If QR fails as well, a system of at most DEFAULT_DENSE_FALLBACK_MAX_N (64) rows and columns is solved densely through an SVD pseudo-inverse; a larger one throws LinearAlgebra.SingularException instead of being densified. Any other error is rethrown. When diagnostics is a dictionary, the backend used (:sparse_backslash, :sparse_qr_fallback or :dense_svd_fallback_small_system), context and the matrix dimensions are written into it.
Sparlectra.AbstractExternalSolver — Type
AbstractExternalSolverExternal solvers should subtype this and implement solvePf(solver, model; kwargs...).
Sparlectra.PFModel — Type
PFModelSolver-agnostic power-flow model extracted from a Net.
Important indexing note:
- The model uses the same "active-bus ordering" as
BusDatareturned bygetBusData(...): sorted by original bus index and excluding isolated buses. Ybusmust be consistent with that ordering. We buildYbususingcreateYBUS(...)which internally compresses indices by removing isolated buses.
Fields:
Ybus: bus admittance matrix (n×n), active buses onlybaseMVA: system base powerbusIdx_net: original bus indices (length n), increasingbusType: :Slack/:PV/:PQ per bus (length n)slack_idx: slack index in PF-ordering (1..n)Vset: voltage magnitude setpoints for PV/Slack buses (length n; dummy 1.0 for PQ)Sspec: specified complex injections in per-unit (length n), P + jQ (net injection)V0: initial complex voltages in per-unit (length n)qmin_pu,qmax_pu: optional PV reactive limits in per-unit (length n, may be empty)
Sparlectra.PFSolution — Type
PFSolutionCommon result object returned by any external solver.
Fields:
V: final complex bus voltages in PF ordering (length n)converged: true if solver reached toleranceiters: iteration/order count (solver-defined)residual_inf: infinity-norm of canonical mismatch (if available)meta: optional solver-specific payload (NamedTuple/Dict/etc.)
Sparlectra.applyPfSolution! — Method
applyPfSolution!(net, model, sol; write_pq_results=true, verbose=0)Write the external solution back into net:
- updates node Vm/Va on all active buses
- optionally writes Slack P/Q and PV Q generation (solved injection plus the bus load, same policy as the rectangular solver)
Notes:
- Isolated buses (not in model) are left untouched.
sol.Vmust be PF-ordered (length n == length(model.busIdx_net)).
Sparlectra.apslf_solver — Method
apslf_solver(; order::Int=24, nr_polish::Bool=false, mode::Symbol=:direct, convergence_radius::Bool=true) -> AbstractExternalSolverReachability point for the AnalyticLoadFlow.jl-backed external solver (ApslfSolver), an analytic power-series (holomorphic-embedding-style) load-flow method.
AnalyticLoadFlow.jl is a required dependency of Sparlectra, so the solver is always available: using Sparlectra is enough, and the result goes straight to solvePf or runpf_external!.
Keyword Arguments
order::Int = 24: highest power-series coefficient to compute.nr_polish::Bool = false: run a Newton-Raphson polishing step on the series result.mode::Symbol = :direct::direct(native PV handling) or:outer(PQ-only series plus an outer secant loop for PV enforcement).convergence_radius::Bool = true: evaluate and report the Padé-pole margin (the APSLF convergence radius).
Sparlectra.buildPfModel — Method
buildPfModel(net; opt_sparse=true, flatstart=net.flatstart, include_limits=true, verbose=0) -> PFModelBuild a canonical PF model from net:
- active buses are defined via
getBusData(net.nodeVec, net.baseMVA, flatstart; net=net), which excludes isolated buses and sorts by bus index. - Ybus is built via
createYBUS(net=net, sparse=opt_sparse, ...)and is consistent with the same isolated-bus compression. - the voltage setpoint
Vsetof a slack or PV bus is the setpoint of its regulating generator, with the node voltage and 1.0 pu as fallbacks, the same lookup the rectangular solver uses.
include_limits=true attaches qmin/qmax in per-unit as used by your NR-with-limits code.
Sparlectra.mismatchInf — Method
mismatchInf(model, V) -> Float64Compute ||F(V)||_∞ using Sparlectra's rectangular PQ/PV mismatch definition:
F = mismatch_rectangular(model.Ybus, V, model.Sspec, model.busType, model.Vset, model.slack_idx)This is the canonical comparison metric for external solvers.
Sparlectra.runpf_external! — Method
runpf_external!(net, solver; tol=1e-8, opt_sparse=true, flatstart=net.flatstart, include_limits=false, verbose=0, solver_kwargs...) -> (iters, status, sol)Convenience wrapper:
- build model from net
- call external
solvePf(solver, model; solver_kwargs...) - compute canonical mismatch infinity norm (unless solver provided it)
- apply solution back to net
- return
(iters, status, sol)wherestatus == 0indicates convergence
include_limits=false by default: keep Sparlectra "clean" and let external solver decide.
Sparlectra.solvePf — Method
solvePf(solver, model; kwargs...) -> PFSolutionExternal solver hook. Must be implemented by the external solver package.
The returned voltage vector sol.V must be in PF ordering (model.busIdx_net order).
Sparlectra.SparlectraRunResult — Type
SparlectraRunResultTyped result returned by run_sparlectra. The solved network is always available as net, while the remaining fields provide stable framework-level solver, validation, control-loop, timing, and rectangular diagnostic metadata.
Internals
Sparlectra._run_apslf_powerflow! — Method
_run_apslf_powerflow!(net, pf_cfg; verbose=0, performance_profile=nothing) -> (iterations::Int, erg::Int)Solve net with the AnalyticLoadFlow.jl-backed APSLF solver (power_flow.solver = :apslf) instead of the internal rectangular Newton-Raphson path. Mirrors the internal path's parallel-link merge (_merged_pf_net) and per-island handling (detect_ac_islands, _prepare_island_net, _sync_island_solution!): one PFModel is built and solved per active AC island via runpf_external!. Writes a rectangular_pf_status-compatible status onto net so result building, reporting, logs, and the generic AC island diagnostics writer treat this run on the same contracts as the NR route.
power_flow.qlimits.ignore_q_limits is honored (Q-limits are passed to the solver unless explicitly disabled); all other rectangular-only start/damping/ Q-limit-switching options do not apply and are ignored, since APSLF always starts from its own canonical analytic germ and performs its own internal PV/Q-limit handling.
Callers must reject active controllers before calling this function; it does not check for them itself. That covers the outer-loop tap/PST controllers and the voltage-dependent Q(U)/P(U) controllers, which are not outer-loop: they act inside the rectangular Newton step and have no counterpart here.
Sparlectra.AutoPfDecision — Type
AutoPfDecisionResult of select_auto_pf_strategy: the selected profile, the dotted-key options the profile wants, and one human-readable reasons entry per triggered rule.
Sparlectra.AutoPfFeatures — Type
AutoPfFeaturesRead-only summary of an imported network, the input of select_auto_pf_strategy. Produced by collect_auto_pf_features in one pass over buses, branches, and prosumers; no factorization, no solve, no mutation.
Sparlectra._apply_auto_pf_options — Method
_apply_auto_pf_options(pf, options, user_set_keys) -> (pf2, applied, conflicts)Apply the decision options onto a PowerFlowConfig copy. Keys the user set explicitly (dotted keys in user_set_keys) are NEVER overwritten; they are returned in conflicts as "key kept by user" entries for the decision log.
Sparlectra._execute_auto_sparlectra_powerflow! — Method
_execute_auto_sparlectra_powerflow!(net, cfg; performance_profile) -> executionAuto-mode drive of the power flow: feature extraction, strategy selection, precedence-safe application, base attempt, and the bounded escalation ladder. The record (features, decision, attempts, hints) is stored on the net (auto_pf_record) for the service layer. Tolerance is never changed by any stage.
Sparlectra._write_auto_mode_decision_log — Method
_write_auto_mode_decision_log(path, rec)Write the human-readable auto-mode decision artifact: feature summary, selected profile with per-rule reasons, applied options, precedence conflicts (user key kept), every escalation attempt with its changed keys, solver path, iteration count and Q-limit evidence, and the hint list.
Sparlectra.auto_pf_hints — Method
auto_pf_hints(features, evidence, attempts; converged) -> Vector{NamedTuple}Generate the advisory hint list from the recorded diagnostics: each entry is (id = :stable_key, text = "..."). Purely derived from existing diagnostics; hints never mutate configuration or behavior.
Sparlectra.auto_pf_record — Method
auto_pf_record(net) -> Union{Nothing,NamedTuple}The auto-mode decision/escalation record of the most recent auto run on this net (nothing when the run was manual).
Sparlectra.collect_auto_pf_features — Method
collect_auto_pf_features(net::Net; min_q_range_pu = 1e-4) -> AutoPfFeaturesExtract the auto-mode decision features from an imported network. Pure read-only and format independent: format specifics end at import, this works the same on MATPOWER, CGMES, and DTF nets. min_q_range_pu is the narrow-range threshold the Q-limit guard uses (power_flow.qlimits.guard_min_q_range_pu).
Sparlectra.select_auto_pf_strategy — Method
select_auto_pf_strategy(features::AutoPfFeatures) -> AutoPfDecisionSelect the auto-mode profile and option set for a network: an ordered rule list picks the profile (first match wins), then profile-independent feature gates add islands handling, Q-limit strategy, and plausibility checks. Thresholds live in AUTO_PF_THRESHOLDS.
Sparlectra._cgmes_start_values_powerflow — Method
_cgmes_start_values_powerflow(pf_cfg, start_values) -> (PowerFlowConfig, overridden::Vector{String})Apply cgmes_import.start_values to the power-flow configuration of one CGMES run. :flat forces a synthetic flat start; :sv keeps the imported SvVoltage state and force-disables every competing start-value machine — the same set the fixed-reference self-check forces off in _self_check_forced_overrides (runselfcheck.jl); keep the two lists aligned. Returns the adjusted config plus the effective config keys that were overridden (for the decision line in run.log/cgmes.log). MATPOWER/DTF runs never call this.
Sparlectra._flatstart_profile_config — Method
_flatstart_profile_config(cfg) -> (SparlectraConfig, overridden::Vector{String})The flat start chooses the voltage PROFILE a run starts from and nothing else (#463): with power_flow.flatstart = true every bus starts at 1.0 pu (PV and slack buses at their setpoints) and 0 degrees instead of the imported voltages, and every start machine follows its own key and works from that flat profile: the start projection with its DC, blend and ratio-profile candidates (start_mode.start_projection), the unconditional DC seed (start_mode.dc_seed_unconditional), the current-iteration pre-solve (start_current_iteration.enabled) and the APSLF start (apslf_start.enabled). Before #463 the flat start switched all of them off, so "projection from a flat start" could not be configured as written.
What the flat start still overrides are the two start MODES, because they choose a profile as well: voltage_mode and the imported-angle angle_modes read the stored columns (the MATPOWER import applies them only under a flat start and would turn it into a blended imported start), and angle_mode = dc makes the DC angles a requested start that excludes the measured candidates. Both go classic for this run; the DC angles stay available as the projection's measured DC candidate (try_dc_start). The stored configuration is left as it is (the Web UI greys the two mode controls while the flat start is on); the returned list names every overridden key for the run log.
Sparlectra._net_cache_load — Method
_net_cache_load(path, components) -> Union{Nothing,SCFCase}Returns the cached CONVERTED case (stored as its canonical SCF JSON) or nothing. Beyond the key in the file name, the stored component list must match exactly, and the JSON goes through the reader's parse and conversion, so a stale or truncated artifact silently misses instead of producing a wrong case.
Sparlectra.non_slack_indices — Method
non_slack_indices(n, slack_idx) -> Vector{Int}Sparlectra.reduce_susceptance_to_nonslack — Method
reduce_susceptance_to_nonslack(Bsrc, non_slack, pos, slack_idx, nred; value_of=imag) -> B_reducedEliminate the slack row/column from a full n×n susceptance-like source matrix and return the (n-1)×(n-1) reduced system used by any DC-angle linear solve (_solve_dc_angle_system). value_of extracts the real susceptance entry from Bsrc[i,j]: imag for a complex Ybus (the rectangular-solver DC-angle start-value heuristic, which reduces the full AC admittance matrix), identity for an already-real B′ (a true DC power-flow matrix, series reactance only). Sparse Bsrc in gives a sparse result; dense in gives dense out. Shared between rundcpf!'s B′ reduction and the rectangular solver's internal DC-angle start projection so the two call sites never diverge into two slack-elimination implementations.
Sparlectra.showPfModel — Method
showPfModel(model; io=stdout, verbose=false)Print a compact human-readable summary of the PFModel. This is intentionally separate from Base.show(model) to avoid global display side effects.
Sparlectra.showPfSolution — Method
showPfSolution(sol; io=stdout)Print a compact human-readable summary of a PFSolution.
Sparlectra._apply_start_modes! — Method
_apply_start_modes!(net, case, start_cfg; performance_profile) -> NothingApply the configured start voltage and angle modes with the RAW source start values of case.sparlectra.start_state as the reference profile. PV and slack classification and the resolved voltage setpoints come from the built net itself: the adapter resolved the source system's setpoint choice at conversion time, so the historical distinction between the raw generator setpoint and the imported setpoint collapses onto the value the machines actually regulate to.
Sparlectra._matpower_raw_starts — Method
_matpower_raw_starts(mpc) -> VectorThe raw per-bus start voltages of a parsed MATPOWER case, index-aligned with the direct import's node order (which is the bus row order).