Multi-scenario sweep#

sweep(base_case, scenarios, *, solver='dc_opf', paths=(), keep_results=False, max_results=1000, seed=None, n_threads=0, portfolio=None, settlement_net=None, points=None, **solver_kwargs)#

Solve a set of scenarios and aggregate their price distributions.

Parameters:
  • base_case -- Case to modify for each scenario.

  • scenarios -- Iterable of Scenario objects to solve.

  • solver -- "dc_opf", "dc_scopf", "sced", or a compatible callable.

  • paths -- (source_bus, sink_bus) pairs for path-price distributions.

  • keep_results -- Retain individual solver results for inspection.

  • max_results -- Maximum number of retained successful results. The sweep still solves and aggregates later scenarios.

  • seed -- Random seed to record with the result.

  • n_threads -- Worker count. Zero selects the default.

  • portfolio -- Optional FTR portfolio to value across every result.

  • settlement_net -- Prepared DC network for FTR revenue-adequacy checks.

  • points -- Settlement points keyed by customer name for FTR valuation.

  • solver_kwargs -- Additional arguments for the selected solver.

Returns:

A SweepResult. distribution contains single-period LMP, congestion, branch-use, and requested path statistics. results and result_labels contain retained successful results. failed contains (label, reason) pairs. A SCED sweep returns its retained period results and sets distribution to None.

Examples

>>> import gpf
>>> case = gpf.load_case("case.raw")
>>> scenarios = [
...     gpf.load_scenario(1.10, label="peak"),
...     gpf.outage_scenario((101, 205, "1"), label="line outage"),
... ]
>>> result = gpf.sweep(case, scenarios, keep_results=True)
>>> result.n_scenarios
2
class Scenario(label, outages=frozenset({}), demand_scale=1.0, scale_kwargs=(), cost_scale=1.0, gen_cost_scale=(), pg0=(), durations=())#

Declare one operating condition for a distribution sweep.

The scenario constructors provide the simplest interface for one type of change. Construct Scenario directly when one condition combines an outage with load, cost, or SCED changes. Direct construction uses immutable tuples because the object is frozen.

label#

Customer name for the condition.

Type:

str

outages#

Branches to remove. Each branch uses the case identity (from_bus, to_bus, circuit_id).

Type:

frozenset

demand_scale#

Multiplier for the selected in-service load.

Type:

float

scale_kwargs#

Load selection and reactive-power options as ((name, value), ...). Convert list values, such as bus or area selections, to tuples. See load_scenario for the option names.

Type:

tuple

cost_scale#

Positive multiplier for every generator cost curve.

Type:

float

gen_cost_scale#

Additional positive cost multipliers as (((bus, generator_id), multiplier), ...).

Type:

tuple

pg0#

Initial generator outputs as (((bus, generator_id), output_mw), ...). This field applies only to a SCED sweep.

Type:

tuple

durations#

Positive period lengths in hours. This field applies only to a SCED sweep and must match the dispatch horizon.

Type:

tuple

Examples

Scale all in-service loads to 110 percent of their base values:

>>> import gpf
>>> scenario = gpf.load_scenario(1.10, label="summer peak")

Scale loads in area 2 and remove branch 101-205-1 in separate conditions:

>>> area_peak = gpf.load_scenario(1.08, areas=[2])
>>> line_out = gpf.outage_scenario((101, 205, "1"))

Combine the same load and outage changes in one condition:

>>> combined = gpf.Scenario(
...     "area 2 peak with line outage",
...     outages=frozenset({(101, 205, "1")}),
...     demand_scale=1.08,
...     scale_kwargs=(("areas", (2,)),),
... )
property topology_key#

Return the network identity for this scenario.

property has_cost_overlay#

Return true when this scenario changes generator costs.

materialize(base_case)#

Apply this scenario to a copy of base_case and return it.

class SweepResult(distribution, n_scenarios, n_networks, results=<factory>, result_labels=<factory>, results_capped=False, failed=<factory>, seed=None, valuation=None)#

Store aggregate and retained results for a scenario sweep.

distribution contains the requested price statistics. results and result_labels contain retained successful results when requested. failed identifies conditions that did not solve. The result also reports coverage, retained-result limits, the random seed, and optional valuation.

to_json()#

Return a JSON-compatible sweep result.

class Distribution(paths=())#

Aggregate bus prices, branch use, and path spreads without storing cases.

Congestion is lmp - lmp_energy. It includes the full non-energy price that settles an FTR, including security for a security-constrained result. Bus numbers and branch keys identify all values.

set_ratings(keys, rates)#

Register per-branch ratings (MW) for binding / utilization; a branch with no positive rating is excluded from branch statistics.

update(result)#

Fold one solved OPF result (DC-OPF or DC-SCOPF) into the distributions.

summary()#

Native-keyed distributions (bus ints, branch_key / path tuples).

to_json()#

Return distributions with stringified tuple keys.

This aggregate is not a queryable point-result surface. Point results use to_json for a header and as_tables for their row data.

class ScenarioSweepError#

A sweep could not be posed: a mis-declared topology, an unknown solver.

load_scenario(multiplier, *, label=None, **scale_kwargs)#

Create a scenario that scales selected in-service loads.

Parameters:
  • multiplier -- Multiplier for the selected active demand. For example, 1.05 adds 5 percent and 0.90 removes 10 percent.

  • label -- Customer name for reports. The function creates a label when this value is omitted.

  • scale_kwargs -- Optional load selectors and reactive-power settings. areas, zones, owners, and buses accept sequences of case identifiers. bus_type accepts None, "pq", or "pv_slack". interruptible accepts "both", "non_interruptible", or "interruptible". All supplied selectors must match a load. q_mode accepts "scale" (default), "preserve", "zero", "target", "percent", "pf", or "increment". The last four modes require q_target_mvar, q_percent, q_target_pf, or q_increment_mvar, respectively.

Returns:

A scenario for sweep.

Examples

Scale active and reactive load at buses 101 and 205 by 5 percent:

>>> scenario = gpf.load_scenario(1.05, buses=[101, 205])

Scale active load in area 2 and preserve its reactive load:

>>> scenario = gpf.load_scenario(
...     1.10, areas=[2], q_mode="preserve", label="area 2 peak"
... )
outage_scenario(keys, *, label=None)#

Create a scenario that removes one or more branches from service.

Parameters:
  • keys -- One (from_bus, to_bus, circuit_id) identity or an iterable of these identities. Bus numbers are integers. The circuit ID is the case value, such as "1".

  • label -- Customer name for reports. The function creates a label when this value is omitted.

Returns:

A scenario for sweep.

cost_scenario(multiplier=1.0, *, gens=None, label=None, demand_scale=1.0, **scale_kwargs)#

Create a scenario that changes generator costs and optional demand.

Parameters:
  • multiplier -- Positive factor for all generator cost curves.

  • gens -- Optional additional positive factors keyed by (bus, generator_id). A generator receives both the common and its named factor.

  • label -- Customer name for reports. The function creates a label when this value is omitted.

  • demand_scale -- Multiplier for selected active demand.

  • scale_kwargs -- Optional load selectors and reactive-power settings accepted by load_scenario.

Returns:

A scenario for sweep.

Raises:

ValueError -- A common or generator-specific cost factor is not positive.

Examples

Increase all costs by 10 percent and apply an additional 20 percent increase to generator 101-1:

>>> scenario = gpf.cost_scenario(
...     1.10, gens={(101, "1"): 1.20}, label="high fuel cost"
... )
pg0_scenario(pg0, *, label=None, demand_scale=1.0, **scale_kwargs)#

Create an initial-dispatch condition for a SCED scenario.

Parameters:
  • pg0 -- Initial MW values keyed by (bus, generator_id).

  • label -- Customer name for reports. The function creates a label when this value is omitted.

  • demand_scale -- Multiplier for selected active demand.

  • scale_kwargs -- Optional load selectors and reactive-power settings accepted by load_scenario.

Returns:

A scenario for sweep(..., solver="sced").

Raises:

ValueError -- pg0 is empty.

Examples

Set the initial output of generator 101-1 to 250 MW:

>>> scenario = gpf.pg0_scenario({(101, "1"): 250.0})
duration_scenario(durations, *, label=None, demand_scale=1.0, **scale_kwargs)#

Create a period-duration condition for a SCED scenario.

Parameters:
  • durations -- Positive period lengths in hours. The number of values must match the dispatch horizon.

  • label -- Customer name for reports. The function creates a label when this value is omitted.

  • demand_scale -- Multiplier for selected active demand.

  • scale_kwargs -- Optional load selectors and reactive-power settings accepted by load_scenario.

Returns:

A scenario for sweep(..., solver="sced").

Raises:

ValueError -- durations is empty or contains a nonpositive value.

Examples

Use one 30-minute period followed by two one-hour periods:

>>> scenario = gpf.duration_scenario([0.5, 1.0, 1.0])
monte_carlo_load_scenarios(n, *, seed, sigma=0.1, mean=1.0, label_prefix='mc', **scale_kwargs)#

Create reproducible load scenarios from a normal distribution.

The function clips each sampled multiplier to a minimum of 0.01.

Parameters:
  • n -- Number of scenarios to create.

  • seed -- Random seed. The same inputs and seed produce the same scenarios.

  • sigma -- Standard deviation of the load multiplier.

  • mean -- Mean load multiplier.

  • label_prefix -- Prefix for each generated scenario label.

  • scale_kwargs -- Optional selectors and reactive-power settings accepted by load_scenario.

Returns:

A list of n load scenarios.

Examples

Create 100 load scenarios for area 2 with a 10 percent standard deviation:

>>> scenarios = gpf.monte_carlo_load_scenarios(
...     100, seed=7, sigma=0.10, areas=[2]
... )