Scenario studies#
- class Study(base_case=None, *, name='study', backend=None, options=None)#
Build, load, and run a file-first contingency study.
Use
sweep()andScenariofor in-memory price and congestion distributions. This class owns auditable study definitions and reports.- Parameters:
base_case -- Base network as a
GpfCaseor as a path thatload_casesupports.Nonepermits the caller to set a case later or passcase=toplanorrun.name -- Study name used in reports and stored results.
backend -- Backend name to store with the study definition. Pass a backend to
plan,run, orscreento select it for that operation.options -- Default
PfSolveOptionsfield names and values. A call torunorscreencan override these values.
- classmethod wrap(defn, *, study_dir=None, case=None, capture=<function capture_file>)#
Build a study from a parsed definition without reading a file.
- Parameters:
defn -- Parsed study definition.
study_dir -- Directory used to resolve relative paths in
defn.case -- Optional loaded case. This value takes precedence over the base-case path in
defn.capture -- Read the case bytes and content revision as one value.
- Returns:
A study that holds the supplied definition and case context.
- baseline()#
Return this study without its modeled additions.
The delta study runs the result against the study itself to attribute each violation to the
[[addition]],[[project]], and[[load]]blocks.- Raises:
ValueError -- The study declares no additions, so there is nothing to attribute.
- classmethod from_toml(path)#
Load a study definition from a TOML file.
Relative case paths in the file resolve against the file's directory.
- Parameters:
path -- Study TOML file.
- Returns:
The parsed study. The method does not load or solve the base case.
- Raises:
OSError -- The file cannot be read.
StudyFormatError -- The TOML content is invalid.
- to_toml(path=None)#
Serialize the study definition as TOML.
- Parameters:
path -- Optional output file.
Noneperforms no file write.- Returns:
The complete TOML text.
- Raises:
OSError -- The output file cannot be written.
- primary_case_path()#
Return the first case path that this study resolves.
- Returns:
The base-case path or the first seasonal case path.
Nonemeans that the study holds an in-memory case or has no case.
- set_base_case(path)#
Set one base-case file and remove any seasonal case set.
- Parameters:
path -- Case file that
load_casesupports.- Returns:
This study, which permits fluent calls.
- set_base_cases(paths)#
Set a seasonal case set with one case per path.
This setting overrides
base_caseand any case blocks. Each case receives the file stem as its report name. Use case blocks in TOML when each case needs a separate dispatch assumption.- Parameters:
paths -- Case files that
load_casesupports. The method resolves each path against the current working directory.- Returns:
This study, which permits fluent calls.
- classmethod from_psse(con, *, sub=None, mon=None, base_case=None)#
Import a study from PSS/E study-definition files.
- Parameters:
con -- Required PSS/E contingency file.
sub -- Optional PSS/E subsystem file referenced by the study.
mon -- Optional PSS/E monitor file.
base_case -- Optional base-case path to store in the imported definition.
- Returns:
The imported study. Relative paths resolve against the directory that contains
con.- Raises:
OSError -- An input file cannot be read.
StudyFormatError -- An input declaration is invalid or unsupported.
- with_options(**opts)#
Set default power-flow solve options.
- Parameters:
opts --
PfSolveOptionsfield names and values. New values replace existing defaults with the same names.- Returns:
This study, which permits fluent calls.
- Raises:
StudyFormatError -- An option name or value is invalid.
- with_dispatch(op, **params)#
Append an ordered base-case dispatch operation.
The study applies each operation to a working copy before it solves the case. It does not modify the caller's case.
- Parameters:
op -- A scaling op name, such as
"scale_loads".params -- Arguments for the matching scaling function.
dispatch_generatorstakesgroup, the name of a declared machine group, in place ofmachines. The group must exist when the study runs.
- Returns:
This study, which permits fluent calls.
- Raises:
ValueError -- The operation or one of its parameters is invalid.
- with_group(name, machines)#
Define a generator group for redispatch.
- Parameters:
name -- Group name used by
with_dispatchand contingency injections.machines -- Iterable of
(bus, unit_id, factor)entries. The factors define relative participation and need not sum to one.
- Returns:
This study, which permits fluent calls. A repeated name replaces the previous group.
- monitor(*, scope=None, voltage_band=None, emergency_band=False, branches=None, branch_scope=None, base_rating_set=1, contingency_rating_set=1, loading_basis='case', missing_rating='incomplete', thermal_threshold_pct=100.0, interface_base_rating_set=1, interface_contingency_rating_set=1, rating_set=<unset>)#
Set the voltage and branch criteria for study results.
- Parameters:
scope -- Buses whose voltage is judged.
Nonemonitors all buses when a voltage criterion is active.voltage_band -- Optional inclusive
(low, high)voltage band in per unit.emergency_band -- Use each bus record's emergency low and high limits. These limits take precedence over
voltage_band.branches -- Explicit monitored branches. Each entry is a
MonitoredBranchor a(from_bus, to_bus, circuit_id)tuple. A two-item tuple uses circuit ID"1".branch_scope -- Adds the branches anchored inside it to the explicit branch list.
base_rating_set -- Exact rating slot used for the base condition.
contingency_rating_set -- Exact rating slot used after an outage.
loading_basis --
casereads XFRRAT and NXFRAT.mvaandcurrentoverride the case flags.missing_rating --
incompleterecords missing limits.errorrefuses the run.thermal_threshold_pct -- Loading percentage that defines a reported branch violation.
- Returns:
This study, which permits fluent calls. This call replaces the previous monitor declaration.
- Raises:
StudyFormatError -- The rating set is outside the supported range.
StudyResolveError -- A scope or branch cannot be resolved when the study runs.
- property criteria#
Return the criteria this study judges scenarios against, with the thermal default a single-branch rule implies.
- sweep(family='branch', scope=None)#
Append a sweep: every outage of one device family inside a scope.
- Parameters:
family --
"branch"takes out each in-service branch in turn."generator"takes out each in-service machine in turn.scope -- A branch qualifies when all of its real endpoints are in the scope, and a machine when its bus is.
Nonecovers the full case.
- Returns:
This study, which permits fluent calls.
- retain(policy)#
Set how the result retains solved voltage arrays.
- Parameters:
policy --
"summary"keeps compact screening results and can replay a scenario for details."file"writes voltage arrays to the result sidecar.- Returns:
This study, which permits fluent calls.
- Raises:
StudyError -- The policy is not
"summary"or"file".
- add_contingency(label, *, branches=(), gens=(), injection=None)#
Append a named contingency.
- Parameters:
label -- Customer-facing scenario name.
branches --
(from_bus, to_bus, circuit)identities taken out together.gens --
(bus, machine id)identities taken out together.injection -- Optional ordered
DispatchGroupvalues that shift generation across a declared group for this contingency.
- Returns:
This study, which permits fluent calls.
- Raises:
StudyResolveError -- A device identity cannot be resolved when the study runs.
- has_base_case()#
Report whether the study can resolve a base case by itself.
- Returns:
True when the study holds a case, a base-case path, or at least one seasonal case. False means that
planorrunneedscase=.
- case_runs()#
Load the operating cases declared by this study.
- Returns:
One
CaseRunfor a plain base case, or one per seasonal case. Each item contains the report name, loadedGpfCase, and theStudyDefinitionwith that case's dispatch assumption applied.- Raises:
StudyError -- The study has no usable case.
OSError -- A declared case file cannot be read.
- working_case(case=None)#
Build the case that this study will solve.
The method applies additions first and ordered dispatch operations second. It applies them to a copy when a transform is required.
- Parameters:
case -- Optional base-case override.
Noneuses the study's held or declared case.- Returns:
(case, additions, dispatch).caseis the transformedGpfCase. The two lists contain customer-readable records of the applied additions and dispatch changes.- Raises:
StudyError -- The study has no usable base case.
StudyResolveError -- An addition, dispatch group, or referenced device cannot be resolved.
- plan(*, case=None, backend=None)#
Resolve and validate the contingency plan without solving it.
- Parameters:
case -- Optional case override.
Noneuses the case held by the study or the case path in its definition.backend -- Backend used to prepare the network.
Noneuses normal backend selection.
- Returns:
Named and swept
Contingencyvalues in run order. The list omits the implicit base scenario at index 0.- Raises:
StudyError -- The study has no usable base case.
StudyResolveError -- A scope, action, monitor, or device identity cannot be resolved against the case.
- solver_args(*, ac=False)#
Return the study's monitored branches and voltage band for the solver entry points.
- Parameters:
ac -- Include the study's common voltage band when true.
- Returns:
(monitored, voltage_band).monitoredholds the monitor's explicit branch identities, orNone.
- run(*, case=None, backend=None, progress='auto', label=None, **opts)#
Solve the base condition and every resolved contingency.
- Parameters:
case -- Optional case override.
Noneuses the case held by the study or the case path in its definition. Additions and ordered dispatch operations apply to a copy of this case.backend -- Solver backend.
Noneuses normal backend selection.progress --
"auto"displays progress on an interactive standard error stream.Truealways displays it.Falsedisables it. A callable receives the run's progress frames: "Base case" without a total, then "Contingencies" counted over every scenario. A true return value requests cancellation.label -- Optional prefix of the frame names, so a run that is one half of a comparison names its half.
opts --
PfSolveOptionsfield names and values. These values override defaults set throughoptionsorwith_options.
- Returns:
A
StudyResult.basecontains scenario 0.scenarioscontains evaluated contingencies.refusedcontains conditions with invalid topology. The result also contains configured voltage, branch, and interface violations, worst-condition envelopes, customer tags, and run metadata. Voltage values use per unit, branch loading uses MVA and percent, and interface flows use MW.- Raises:
StudyError -- The study has no base case or the run cannot produce a valid study result.
StudyResolveError -- A scope, action, monitor, interface, dispatch group, or device identity cannot be resolved.
PfSolveAborted -- The progress callback requests cancellation.
- screen(*, case=None, backend=None, base_flows='ac', nominal_taps=False, **opts)#
Rank N-1 branch outages with a fast linear screen.
The screen anchors on the base flows and redistributes them with DC line outage distribution factors, streamed in bounded memory. It does not perform AC contingency solves. Use
runfor final results.- Parameters:
case -- Optional case override.
Noneuses the case held by the study or the case path in its definition.backend -- Solver backend.
Noneuses normal backend selection.base_flows -- Where the linear model takes its base flows.
"ac"solves the AC base case and starts from its flows."dc"starts from lossless DC flows.nominal_taps -- Ignore transformer tap ratios in branch susceptance.
opts --
PfSolveOptionsfield names and values for the base solve. These values override study defaults.
- Returns:
A
ScreeningResult.rankedcontains single-branch outages in descending estimated loading order, islanding outages included.unscreenablecontains conditions that require a full solve.- Raises:
StudyError -- The base condition does not converge, or
base_flowsnames no known anchor.StudyResolveError -- The study has no monitored branches or a study reference cannot be resolved.
- propose_corrections(study, result, *, max_rounds=3, margin_pct=2.0, max_shed_fraction=1.0)#
Propose and verify controls for each violating contingency.
The function uses generator dispatch, transformer controls, shunts, and load curtailment that the study permits. It verifies each proposal with an AC solve and can resize the proposal through
max_rounds.- Parameters:
study -- Study definition and base case.
result -- Completed contingency study result.
max_rounds -- Maximum AC verification and resize rounds.
margin_pct -- Extra correction margin for sensitivity error.
max_shed_fraction -- Maximum fraction of each active load that can be curtailed.
- Returns:
Proposed actions and their verified status for each violation.
- class CorrectiveReport(name: 'str', corrections: 'list[ContingencyCorrection]', meta: 'dict[str, Any]'=<factory>)#
- status_counts()#
Return the number of corrections in each status.
- to_dict()#
Return a JSON-compatible corrective report.
- to_json(path=None)#
Return the report as JSON and optionally write it to
path.
- to_markdown(path=None)#
Return the report as Markdown and optionally write it to
path.
- class ContingencyCorrection(label, status, reason, actions=<factory>, rounds=0, worst_branch=None, initial_pct=None, final_pct=None, residual_mw=None, new_violations=<factory>)#
The correction outcome for one violating contingency.
- property total_shift_mw#
Return the total absolute generator redispatch in MW.
- to_dict()#
Return a JSON-compatible contingency correction.
- class CorrectiveAction(bus, machid, delta_mw, action_type='gen_redispatch', weight=1.0)#
One generator MW move.
- to_dict()#
Return a JSON-compatible generator redispatch action.
- class PhaseShifterAction(from_bus, to_bus, ckt, delta_deg, new_deg, action_type='phase_shifter', weight=3.5)#
One phase-shifter angle move (degrees, winding-1 convention).
- to_dict()#
Return a JSON-compatible phase-shifter action.
- class TapAction(from_bus, to_bus, ckt, delta_ratio, new_ratio, action_type='tap', weight=50000.0)#
One voltage-controlling tap move (winding-1 pu ratio).
- to_dict()#
Return a JSON-compatible transformer-tap action.
- class ShuntAction(bus, delta_mvar, new_mvar, action_type='switched_shunt', weight=1.0)#
One switched-shunt move (Mvar at 1 pu).
- to_dict()#
Return a JSON-compatible switched-shunt action.
- class LoadCurtailmentAction(bus, loadid, delta_mw, action_type='load_shed', weight=100.0)#
One load-shed move (MW curtailed at constant power factor).
- to_dict()#
Return a JSON-compatible load-curtailment action.
- class OfflineGenStartAction(bus, machid, pg_mw, action_type='offline_gen_start', weight=2.0)#
One off-line generator brought online at a corrective active output (MW, reactive pinned to zero).
- to_dict()#
Return a JSON-compatible generator-start action.
- class GeneratorSetpointAction(bus, machid, delta_pu, new_setpoint, group, action_type='generator_setpoint', weight=1600.0)#
One generator voltage-setpoint move (pu at the regulated bus). Emitted per member device of the moved regulator group;
group(the regulated target bus) ties the members of one group move together.- to_dict()#
Return a JSON-compatible generator-setpoint action.
- class ShuntSetpointAction(bus, delta_pu, new_setpoint, group, action_type='swshunt_setpoint', weight=1600.0)#
One MODSW=2 continuous switched-shunt setpoint move: the regulation band is shifted (both edges by
delta_pu, width preserved) so its midpoint setpoint moves.groupties co-regulating members together.- to_dict()#
Return a JSON-compatible shunt-setpoint action.
- class StudyDefinition(name='study', base_case=None, cases=<factory>, backend=None, options=<factory>, groups=<factory>, additions=<factory>, projects=<factory>, load_projects=<factory>, dispatch=<factory>, candidates=None, monitor=None, result_policy='criteria', interfaces=<factory>, contingencies=Contingencies(sweeps=(), named=()), injections=<factory>, costs=<factory>, retain='summary', format=5)#
Define the inputs and options for a scenario study.
formatrecords the study-file schema version. Readers warn when a file uses a newer schema.- for_case(spec)#
This study as it applies in one case of the set: every project's output scaled by that case's dispatch assumption for its fuel kind and service. It sits beside
baseline()because the set of transform fields a case profile touches lives next to the fields. A fraction of 1.0 (the default for an undeclared kind) returns the block untouched, so an empty dispatch table is a literal no-op.
- baseline()#
Return a copy without base-case additions.
- file_references()#
Declare the case sources used by inventory and relocation.
- to_dict()#
Return a JSON-compatible study definition.
- classmethod from_dict(d)#
Build a study definition from a dictionary.
- to_bytes()#
Encode the document with its TOML writer.
- to_toml()#
Return the study definition as TOML.
- classmethod from_toml_text(text)#
Build a study definition from TOML text.
- class StudyResult(name, bus_ids, base, scenarios, meta=<factory>, base_loading=None, voltage_band=None, emergency_band=None, monitored_mask=None, thermal_overloads=None, thermal=None, voltage_violations=None, interface_violations=None, interfaces=None, refused=<factory>, branch_envelope=<factory>, bus_envelope=<factory>, interface_envelope=<factory>, verdict='incomplete', coverage=<factory>, *, base_vm, base_va)#
Store the customer-facing results of a scenario study.
The result contains the base result, scenario summaries, violations, convergence status, and study metadata.
schemalists the result tables.queryruns read-only result queries.solutionandsolutionsreturn complete solved cases when the study retained them.- READOUTS = (Selection(name='overloads', title='Overload report', about='Monitored branches loaded past their rating, worst first.', sql="SELECT scenario, from_bus, to_bus, ckt, pct AS loading_pct, mva AS flow_mva, rating_mva, base_pct AS base_loading_pct FROM violations WHERE type = 'branch_overload' ORDER BY pct DESC", columns={'scenario': Column(quantity=<Quantity.LABEL: ('Label', None, <class 'str'>)>, label='Scenario', description=None, identity=True), 'from_bus': Column(quantity=<Quantity.BUS_REF: ('Bus', None, <class 'int'>)>, label='From bus', description=None, identity=True), 'to_bus': Column(quantity=<Quantity.BUS_REF: ('Bus', None, <class 'int'>)>, label='To bus', description=None, identity=True), 'ckt': Column(quantity=<Quantity.CIRCUIT: ('Circuit', None, <class 'str'>)>, label=None, description=None, identity=True), 'loading_pct': Column(quantity=<Quantity.LOADING: ('Loading', <Unit.PCT: '%'>, <class 'float'>)>, label=None, description=None, identity=False), 'flow_mva': Column(quantity=<Quantity.APPARENT_POWER: ('Apparent power', <Unit.MVA: 'MVA'>, <class 'float'>)>, label='Flow', description=None, identity=False), 'rating_mva': Column(quantity=<Quantity.APPARENT_POWER: ('Apparent power', <Unit.MVA: 'MVA'>, <class 'float'>)>, label='Rating', description=None, identity=False), 'base_loading_pct': Column(quantity=<Quantity.LOADING: ('Loading', <Unit.PCT: '%'>, <class 'float'>)>, label='Base loading', description=None, identity=False)}), Selection(name='voltage', title='Voltage violations', about='Monitored buses outside their band, furthest beyond it first.', sql='SELECT scenario, bus, type AS kind, vm AS vm_pu, "limit" AS limit_pu, base_vm, ABS(vm - "limit") AS beyond_limit FROM violations WHERE type LIKE \'bus_voltage%\' ORDER BY ABS(vm - "limit") DESC', columns={'scenario': Column(quantity=<Quantity.LABEL: ('Label', None, <class 'str'>)>, label='Scenario', description=None, identity=True), 'bus': Column(quantity=<Quantity.BUS_REF: ('Bus', None, <class 'int'>)>, label=None, description=None, identity=True), 'kind': Column(quantity=<Quantity.VIOLATION_KIND: ('Kind', None, <class 'str'>)>, label=None, description=None, identity=True), 'vm_pu': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='V', description=None, identity=False), 'limit_pu': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='Limit', description=None, identity=False), 'base_vm': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='Base V', description=None, identity=False), 'beyond_limit': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='Beyond limit', description=None, identity=False)}), Selection(name='loading', title='Loading table', about="Every monitored branch's flow and loading, highest first.", sql='SELECT scenario, from_bus, to_bus, ckt, pct AS loading_pct, mva AS flow_mva, rating_mva FROM loading ORDER BY pct DESC', columns={'scenario': Column(quantity=<Quantity.LABEL: ('Label', None, <class 'str'>)>, label='Scenario', description=None, identity=True), 'from_bus': Column(quantity=<Quantity.BUS_REF: ('Bus', None, <class 'int'>)>, label='From bus', description=None, identity=True), 'to_bus': Column(quantity=<Quantity.BUS_REF: ('Bus', None, <class 'int'>)>, label='To bus', description=None, identity=True), 'ckt': Column(quantity=<Quantity.CIRCUIT: ('Circuit', None, <class 'str'>)>, label=None, description=None, identity=True), 'loading_pct': Column(quantity=<Quantity.LOADING: ('Loading', <Unit.PCT: '%'>, <class 'float'>)>, label=None, description=None, identity=False), 'flow_mva': Column(quantity=<Quantity.APPARENT_POWER: ('Apparent power', <Unit.MVA: 'MVA'>, <class 'float'>)>, label='Flow', description=None, identity=False), 'rating_mva': Column(quantity=<Quantity.APPARENT_POWER: ('Apparent power', <Unit.MVA: 'MVA'>, <class 'float'>)>, label='Rating', description=None, identity=False)}), Selection(name='non_converged', title='Non-converged', about='Scenarios the solver did not converge, and how each ended.', sql='SELECT label AS scenario, status, exit_reason, iterations, max_mismatch, isolated_buses FROM scenarios WHERE status <> \'converged\' ORDER BY "index"', columns={'scenario': Column(quantity=<Quantity.LABEL: ('Label', None, <class 'str'>)>, label='Scenario', description=None, identity=True), 'status': Column(quantity=<Quantity.STATE: ('State', None, <class 'str'>)>, label='Status', description=None, identity=False), 'exit_reason': Column(quantity=<Quantity.STATE: ('State', None, <class 'str'>)>, label='Exit reason', description=None, identity=False), 'iterations': Column(quantity=<Quantity.COUNT: ('Count', None, <class 'int'>)>, label='Iterations', description=None, identity=False), 'max_mismatch': Column(quantity=<Quantity.MISMATCH: ('Mismatch', <Unit.MVA: 'MVA'>, <class 'float'>)>, label='Max mismatch', description=None, identity=False), 'isolated_buses': Column(quantity=<Quantity.COUNT: ('Count', None, <class 'int'>)>, label='Isolated buses', description=None, identity=False)}), Selection(name='summary', title='Summary', about='One row over every scenario: how many ran, how many failed, and the worst loading and voltage found.', sql="SELECT COUNT(*) AS n_scenarios, SUM(n_violations) AS n_violations, SUM(CASE WHEN status <> 'converged' THEN 1 ELSE 0 END) AS n_non_converged, MAX(worst_branch_pct) AS worst_loading_pct, MIN(min_vm) AS lowest_vm, MAX(max_vm) AS highest_vm FROM scenarios", columns={'n_scenarios': Column(quantity=<Quantity.COUNT: ('Count', None, <class 'int'>)>, label='Scenarios', description=None, identity=False), 'n_violations': Column(quantity=<Quantity.COUNT: ('Count', None, <class 'int'>)>, label='Violations', description=None, identity=False), 'n_non_converged': Column(quantity=<Quantity.COUNT: ('Count', None, <class 'int'>)>, label='Non-converged', description=None, identity=False), 'worst_loading_pct': Column(quantity=<Quantity.LOADING: ('Loading', <Unit.PCT: '%'>, <class 'float'>)>, label='Worst loading', description=None, identity=False), 'lowest_vm': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='Lowest V', description=None, identity=False), 'highest_vm': Column(quantity=<Quantity.VOLTAGE: ('Voltage', <Unit.PU: 'pu'>, <class 'float'>)>, label='Highest V', description=None, identity=False)}))#
The named selections every study result answers.
- classmethod build(name, raw_results, scenarios, bus_ids, meta, *, voltage_band=None, monitored_mask=None, thermal=None, interfaces=None, voltage=(None, []), scalars=None, loading=(None, []), loading_scalars=None, base_loading=None)#
Build a study result from aligned scenario and monitoring outputs.
scenarioscontains(contingency, branch rows, machine rows)entries with the base condition first.raw_resultscontains one matching solve record for each pair.bus_idsmaps voltage columns to case buses.metacontains customer study metadata. The remaining arguments supply optional voltage, branch, and interface criteria and their corresponding results. Per-scenario mappings use scenario indexes.
- min_voltage(s)#
Lowest bus voltage in a scenario as
(vm_pu, bus_number), orNoneif the scenario did not converge.
- max_voltage(s)#
Highest bus voltage in a scenario as
(vm_pu, bus_number), orNoneif the scenario did not converge.
- deviation_from_base(s)#
Largest
|Vm_scenario - Vm_base|and the bus it occurs at, as(dv_pu, bus_number). None unless both the scenario and the base converged.
- band_violations(s)#
Monitored buses outside the
[monitor]voltage band in a scenario, worst-excursion first. Empty when no band is monitored or the scenario is clean.
- branch_overloads(s)#
Monitored branches loaded past their rating in a scenario, worst-loaded first. Empty when thermal monitoring is off or the scenario is clean.
- interface_overloads(s)#
Monitored interfaces whose flow leaves the MW window in a scenario, worst excursion first. Empty when no interface is monitored or the scenario is clean.
- voltages(s, buses)#
Voltage rows for the named buses in one scenario, in request order. Raises
ValueErrornaming any bus not in the case; empty when the scenario did not converge.
- flows(s, *, near_bus=None)#
Loading rows for monitored branches in one scenario, worst-loaded first. These rows are the below-threshold complement of
branch_overloads(), computed from the same resident loading matrix by the samebranch_loading_pct(). Only the monitored set carries flows; empty when thermal monitoring is off, the scenario did not converge, ornear_bustouches no monitored branch.
- worst_loading(s)#
The worst loading among monitored branches in one scenario, in percent of rating, overloaded or not, so a clean case answers its real worst loading rather than nothing. Answered by the solve-time scalar when the fold recorded one, by the loading row otherwise.
Nonewhen thermal monitoring is off, the scenario did not converge, or no monitored branch has a finite loading.
- status_counts()#
Return the number of scenarios in each status.
- converged()#
Return all converged contingency scenarios.
- failed()#
Return all failed contingency scenarios.
- recovered()#
Return recovered scenarios in descending order of shed power.
- swing_machine_trips()#
Scenarios that tripped the last in-service machine at a swing bus. The bus has no P equation, so each solved to the base case; the converged row reports the base, not the outage it names.
- all_scenarios()#
Return every accepted scenario with the base condition first.
- scenario_labels()#
The scenarios a read can be scoped to, by the label
scenarios=[...]takes. A caller that offers this list offers what a scoped read will take.
- by_label(label)#
Return a contingency scenario by label, or
Nonewhen absent.
- scenario(label='base')#
Return a scenario by label.
Raise
KeyErrorwhen the label is absent.
- solutions(labels)#
Return complete solved cases for the requested scenario labels.
The mapping uses scenario indexes as keys. The method raises
KeyErrorfor an unknown label andRuntimeErrorwhen the result cannot provide complete solved states.
- solution(label='base')#
Return the complete solved case for one scenario label.
The method raises
KeyErrorfor an unknown label andRuntimeErrorwhen the result cannot provide complete solved states.
- top_voltage_drops(n=20)#
Scenarios ranked by largest voltage deviation from base.
- worst_low_voltage(n=20)#
Scenarios ranked by lowest bus voltage reached.
- compare_to_base(label, top=10)#
Per-bus voltage deltas vs base for one scenario, worst first. Rows share
voltages()' vocabulary (element/vm/base_vm) plus the ranking keydv.
- explain(label)#
Return a readable explanation of one contingency result.
- query(sql, *, scenarios=None)#
Run a read-only result query and return rows as dictionaries.
Use
scenariosto limit detailed tables to selected results. An omitted scope selects the base case for detailed tables. Callschema()to list the available tables and columns.
- select(sql, *, scenarios=None)#
Run one read-only query and return rows with their column names.
scenariosaccepts labels or indexes for detailed loading, voltage, and device-state tables. An omitted scope selects the base condition for those tables. Summary, criteria, and violation tables cover every scenario. The result includes column names even when no row matches.
- schema()#
Return each available result table and its column names.
A table is absent when the study has no applicable monitoring data, violation, equipment family, or complete solved state for it.
- classmethod column_quantities()#
Return quantity metadata keyed by result table and column.
- dense_tables()#
Return tables that use a scenario scope.
These tables contain loading, voltage, or per-device state. Summary, criteria, and violation tables always cover the complete study.
- dense_coverage()#
Return detailed-table coverage for the last query.
The tuple contains the selected scenario labels and the total scenario count. The method returns
Nonewhen the query used no detailed table.
- headline()#
Return report summary figures calculated across every scenario.
- to_dict(*, include_voltages=False, **_kw)#
The versioned contingency-report document as a dict. OPF-family results use the same name;
to_json()is the indented file/string export built on top of this. Per-scenario rows live in thescenariosprojected table, not in the document.
- to_json(path=None, *, include_voltages=False)#
Return the study result as indented JSON and optionally write it.
- Parameters:
path -- Optional output path.
include_voltages -- Include per-scenario bus voltages.
- Returns:
The JSON document.
Examples
>>> doc = json.loads(result.to_json()) >>> doc["summary"]["worst_contingencies"][0]["label"]
- to_csv(path=None)#
Return scenario summaries as CSV and optionally write them to
path.
- to_markdown(path=None, *, top=20)#
Terminal rendering of the same report document.
- class ScenarioResult(index, label, kind, status, iterations, control_reviews, max_mismatch, exit_reason, isolated_buses=0, shed_gen_mw=0.0, shed_load_mw=0.0, swing_machines_out=(), outage=<factory>, vmin=None, vmin_bus=None, vmax=None, vmax_bus=None, max_dv=None, max_dv_bus=None, worst_pct=None)#
Store the outcome of one study scenario.
The result holds the label, status, convergence figures, and the voltage and loading scalars folded at solve time. Solved arrays live on the study result for the base and in the run store or a replay for every other scenario.
- property converged#
Return true when the scenario converged.
- property recovered#
Converged only by isolating one or more islanded leaves.
- property solution#
Return the complete cached
SolvedCasefor this scenario.
- class ScenarioStudy(case, *, backend=None, **build_kwargs)#
Configure and run a set of power-flow scenarios for one case.
This lower-level interface uses prepared network indexes for branches and generators. Set the scenario count, add outages or generator setpoints, and call
run. Use the context manager so native resources close after use.- Parameters:
case -- Base case for every scenario.
backend -- Solver backend.
Noneuses normal backend selection.build_kwargs -- Network build options accepted by
PfSession.
- property session#
Return the prepared session and its network-index mappings.
The session's
specsupplies the branch and generator indexes that the scenario methods accept.
- set_count(n)#
Set the number of scenarios and clear all existing changes.
- Parameters:
n -- Positive scenario count. Scenario indexes then range from 0 to
n - 1.- Returns:
This scenario study, which permits fluent calls.
- trip_branch(s, branch_idx)#
Remove one branch from one scenario.
- Parameters:
s -- Zero-based scenario index.
branch_idx -- Prepared-network branch index from
session.spec.
- Returns:
This scenario study, which permits fluent calls. Repeated calls can form a multiple-branch outage.
- trip_generator(s, gen_idx)#
Remove one prepared-network generator from scenario
s.A controlled bus stops voltage regulation when the outage removes its last active regulator.
- Parameters:
s -- Zero-based scenario index.
gen_idx -- Prepared-network generator index from
session.spec.
- Returns:
This scenario study, which permits fluent calls. Repeated calls can form a multiple-generator outage.
- set_gen_p(s, gen_idx, pg)#
Set generator active-power values for scenario
s.- Parameters:
s -- Zero-based scenario index.
gen_idx -- One-dimensional prepared-network generator indexes.
pg -- Matching active-power values in per unit on the case system base. A later call replaces an earlier value for the same generator. A value for a removed generator has no effect.
- Returns:
This scenario study, which permits fluent calls.
- run(*, progress_cb=None, **opts)#
Solve all scenarios and return records in scenario order.
- Parameters:
progress_cb -- Optional callable that receives
ScenarioProgressvalues with completed count, total count, and maximum mismatch. A true return value requests cancellation.opts --
PfSolveOptionsfield names and values.
- Returns:
One
BatchScenarioRecordper scenario. Each record contains the status, convergence metrics, service interruption, and bus-voltage arrays in prepared-network bus order. Voltage magnitude uses per unit and angle uses radians. An invalid topology returnsINVALID_TOPOLOGYwith empty voltage arrays.- Raises:
PfSolveAborted -- The progress callback requests cancellation.
- run_streamed(*, mon_idx=None, ifc_idx=None, keep_voltages=True, keep_loading=True, on_voltages=None, on_loading=None, progress_cb=None, fold=None, **opts)#
Solve all scenarios and deliver results through optional callbacks.
Callback arrays remain valid only during the callback. With
fold(seeBackendWrapper.pf_scenario_batch_set_fold) the engine reduces each chunk itself andfold_results()reads the reductions after the solve; when nothing else asks for a per-chunk callback the solve then runs with none, so no worker ever waits on the interpreter.- Parameters:
mon_idx -- Prepared-network branch indexes for apparent-power loading.
Nonedisables branch-loading output.ifc_idx -- Prepared-network branch indexes for signed from-end active flow.
Nonedisables interface-member flow output.keep_voltages -- Retain voltage arrays in returned records when true. False returns empty voltage arrays.
keep_loading -- Retain monitored loading arrays in the returned tuple when true. The loading callback remains active when false.
on_voltages -- Optional
callback(s_index, status, vm, va). Arrays contain a completed group of scenario indexes and their per-unit magnitudes and radian angles.on_loading -- Optional
callback(s_index, status, s_from, s_to, vm_from, vm_to). Apparent-power arrays use MVA. Voltage arrays use per unit.progress_cb -- Optional callable that receives
ScenarioProgressvalues. A true return value requests cancellation.opts --
PfSolveOptionsfield names and values.
- Returns:
A
BatchOutput. Loading arrays have shape(n_scenario, n_monitored). Interface active-flow values have shape(n_scenario, n_interface_branch)in signed MW. An omitted input or disabled retention returnsNonefor its array.- Raises:
PfSolveAborted -- The progress callback requests cancellation.
- property plan#
The decomposition the last solve ran with (see
BackendWrapper.pf_scenario_batch_get_plan), or None before one.
- fold_results()#
The engine's reductions from the last
run_streamed(fold=...).
- materialize(s, **opts)#
Return the complete solved state for scenario index
s.optsaccepts power-flow solve options. Singular and invalid topologies raise an error.
- branch_loading_mva(branch_idx)#
Return governing-end MVA and end flags for each scenario and branch.
branch_idxcontains prepared-network branch indexes. Each returned array has shape(n_scenario, len(branch_idx)). The Boolean array is true where the from end governs. Call this method beforeclose().
- branch_p_from_mw(branch_idx)#
Return signed from-end active branch flow in MW.
branch_idxcontains prepared-network branch indexes. The returned array has shape(n_scenario, len(branch_idx))and uses each branch's from-to orientation. Usebranch_loading_mvafor apparent-power loading. Call this method beforeclose().
- close()#
Release the scenario batch and backend session.
- class ScenarioStatus(*values)#
Identify the outcome state of a study scenario.
- class BatchScenarioRecord(status, iterations, control_reviews, max_mismatch, exit_reason, isolated_buses, shed_gen_mw, shed_load_mw, vm, va, swing_machines_out=())#
Store the customer-visible screening result for one scenario.
The record includes status, convergence information, bus voltages, and any reported service interruption. Use
materializewhen a complete solved case is available and needed.
- class Scope(areas=(), zones=(), owners=(), kv_min=None, kv_max=None, buses=())#
Select buses by area, zone, owner, voltage bound, and bus number.
Connected equipment belongs to the scope. A scope with no criteria selects the whole case.
- property has_filter#
Whether any predicate is set, as opposed to an explicit
buseslist. One owner: a sixth criterion added above is covered here, rather than silently bypassing whichever reader forgot to name it.
- property band#
Return the voltage band as (lo, hi) in kV, infinite where unset.
- to_dict()#
Return a JSON-compatible electrical scope.
- classmethod from_dict(d)#
Build a scope from its JSON or TOML table.
- class Monitor(voltage=None, thermal=None, interfaces=None)#
Define independent voltage and thermal criteria for a study.
- class InterfaceCriteria(base_rating_set=1, contingency_rating_set=1)#
Define exact rating slots for case interfaces.
- to_dict()#
Return the interface criteria in study-wire form.
- class ThermalCriteria(scope=None, branches=(), base_rating_set=1, contingency_rating_set=1, loading_basis='case', missing_rating='incomplete', threshold_pct=100.0)#
Define exact branch thermal limits without a rating fallback.
- to_dict()#
Return the thermal criteria in study-wire form.
- class VoltageCriteria(scope=None, voltage_band=None, emergency_band=False)#
Define the buses and limits used for voltage judgment.
- to_dict()#
Return the voltage criteria in study-wire form.
- class MonitoredBranch(from_bus, to_bus, ckt='1')#
Identify a branch or transformer for loading checks.
- to_dict()#
Return a JSON-compatible monitored branch reference.
- class Contingencies(sweeps=(Sweep(family='branch', scope=None),), named=())#
The outages a screen evaluates: its sweeps and the outages it names.
The default is a single-branch N-1 sweep over the whole case. A declaration with no sweeps and no named outages screens the base operating point alone.
- to_dict()#
Return a JSON-compatible declaration.
- class Contingency(branches=(), gens=(), label='')#
One outage: the branches and machines it takes out together.
branchesholds(from bus, to bus, circuit)identities with the lower bus number first, andgensholds(bus, machine id)identities, both on reported pre-merge bus numbers. An outage naming neither is the base operating point.labelis display text; two contingencies are the same outage when they trip the same devices, which is what results and warm starts join on.- property devices#
Return the identity two contingencies are compared on.
- property family#
Return
"base","branch","generator", or"mixed".
- property name#
the authored one, or the devices tripped.
An outage that trips nothing names the base operating point.
- Type:
Return the display label
- to_dict()#
Return a JSON-compatible contingency.
- classmethod from_dict(d)#
Build a contingency from its JSON or TOML table.
- class Sweep(family='branch', scope=None)#
Every outage of one device family inside a scope.
A sweep stands for the outages it generates rather than listing them, so a solver enumerates it against the network it screens and a whole-system N-1 set never travels as data.
scopeofNonecovers the whole case.- to_dict()#
Return a JSON-compatible sweep.
- classmethod from_dict(d)#
Build a sweep from its JSON or TOML table.
- gpf.BASE_ONLY: Contingencies#
- class AddBus(bus, kv, name='', area=None, zone=None, owner=None)#
A new bus.
area/zone/ownerof None inherit from the existing bus the first added branch/transformer connects it to (resolved at apply).- to_dict()#
Return a JSON-compatible bus addition.
- class AddGenerator(bus, mw, id='1', mva=None, power_factor=None, qmax=None, qmin=None, kind='solar', pmin=0.0, status=1, dispatch_mw=None)#
Add a generator to the study case.
Specify reactive capability with
power_factoror withqmaxandqmin.mwsets maximum active output.dispatch_mwsets its initial output and defaults tomw.- to_dict()#
Return a JSON-compatible generator addition.
- class AddBranch(from_bus, to_bus, ckt='1', r=0.0, x=0.0, b=0.0, rating_mva=0.0, name='')#
A new AC line: pu impedances on the system base, one MVA rating filling rating sets 1-3 (normal = emergency until rated otherwise).
- to_dict()#
Return a JSON-compatible branch addition.
- class AddLoad(bus, mw, id='1', power_factor=0.95, served_mw=None, status=1)#
Add a constant-power load to the study case.
mwsets peak demand.power_factordetermines reactive demand.served_mwsets initial demand and defaults tomw.- to_dict()#
Return a JSON-compatible load addition.
- class AddTransformer(from_bus, to_bus, mva, x_pct, ckt='1', r_pct=0.0, rating_mva=None, name='')#
Add a fixed-ratio two-winding transformer to the study case.
Impedance uses percent on the transformer's
mvabase.rating_mvadefaults tomva.- to_dict()#
Return a JSON-compatible transformer addition.
- class TapLine(from_bus, to_bus, bus, ckt='1', pct=50.0)#
Split a line at a new point-of-interconnection bus.
pctlocates the tap fromfrom_bus. The operation divides impedance, charging, and length between the new segments. Both segments retain the original ratings.- to_dict()#
Return a JSON-compatible line-tap addition.
- class GenerationProjectDef(label, poi_bus, request_mw, resources, siting=None, service='')#
Define one generation interconnection project.
The resources connect at
poi_busor through one optional transformer fromplant_bus.serviceselects the applicable study.- property technologies#
Return the project's technologies in declaration order.
- property output_mw#
Return the project's declared in-service output.
- expand()#
The low-level additions this project denotes, in apply order.
- to_dict()#
Return a JSON-compatible generation project.
- class GenerationResourceDef(mw, technology='solar', id='1', mva=None, power_factor=None, qmax=None, qmin=None, pmin=0.0, status=1, dispatch_mw=None)#
Define one generation technology in an interconnection project.
- addition(bus)#
Return this resource's generator addition at the plant bus.
- property output_mw#
Return the resource's declared in-service output.
- to_dict()#
Return a JSON-compatible generation resource.
- class LoadProject(label, poi_bus, mw, id='1', power_factor=0.95, served_mw=None, status=1, siting=None, service='')#
Define one large-load interconnection project.
The load connects at
poi_busor through an optional transformer fromplant_bus.- expand()#
The low-level additions this load project denotes, in apply order.
- to_dict()#
Return a JSON-compatible load project.
- class Siting(bus, kv, xfmr)#
Connect a project bus to its POI through a transformer.
Generation input calls the transformer
gsuand load input calls itxfmr. Both map to this completebus,kv, andxfmrvalue.from_dict()rejects partial wire declarations.- adds(label)#
The new-bus-plus-transformer pair this siting denotes, in apply order. The caller appends its own device onto the plant bus, which is the only difference between the two project kinds.
- to_dict(key)#
This siting's wire keys, the transformer under the record's own
keyfor it. Optional sub-table entries appear only where given.
- static from_dict(pd, key, where)#
Read a project body's siting, or
Nonewhere the device connects directly at the POI. A body naming any part of one must name all of it; the transformer sub-table is wired plant -> POI from the body, so only its impedance and rating are the author's to give.
- gpf.DispatchOp = Union[ScaleLoads, ScaleGenerators, ScaleShunts, CurtailLoads, DispatchGroup]#
- dispatch_op(op, **params)#
Build one validated dispatch operation from its op name and parameters.
- Raises:
ValueError -- The op is unknown, a parameter is not one the op takes, or a value has the wrong type.
- class DispatchGroup(*, op='dispatch_generators', group, delta_mw, enforce_pt_pb=False)#
The parameters of dispatch_generators().
- class GroupMachine(bus, id, factor)#
One member of an injection group: a machine
(bus, unit id)and thefactorits share of a redispatch is weighted by. The fields are the keys amachinestable spells, so a stray key is refused by name.- cells()#
The member as a
(bus, id, factor)triple.
- to_dict()#
Return a JSON-compatible group member.
- class InjectionGroup(machines=())#
A named set of
GroupMachinemembers that adispatch_generatorsop shifts generation across. Factors are normalized by their sum at apply time, so relative weights are what matter. The study names a group by the key it is stored under.- to_dict()#
Return a JSON-compatible injection group.
- class StudyError#
Base for study-definition problems.
exit_codeis the CLI exit status for this class, so a caller can branch on the failure kind without parsing the message.
- class StudyFormatError#
The study file is structurally wrong (bad table, missing key, bad type, unknown parameter).
- class StudyResolveError#
A contingency references a device not present in the finalized network.
- class ModelSupportError#
The study asks for a capability the solver does not support.
- class CostDecl(bus, id='1', model=2, cost=(), ramp=0.0)#
Declare generator cost and corrective ramp data.
A declaration supplements or replaces the
(bus, id)cost from the case. Model 2 stores highest-order-first polynomial coefficients. Model 1 stores piecewise(p, f)points.rampgives the corrective-window MW budget. Zero lets SCOPF derive a headroom fallback.- to_dict()#
Return a JSON-compatible cost declaration.