dc_flow

DC linearised power-flow constraints (zonal), with optional N-1.

PREP-SHOT's default transmission representation is a "transport" or "pipe" model: net flow trans_export[z1,z2] is bounded by line capacity, and that's it. There's no Kirchhoff voltage law, no loop flow, no reactance -- power can flow whichever way the LP optimum prefers. That's fine for capacity-expansion screening, where the question is "where to build" rather than "what does the AC network actually do."

When config.json.dc_parameters.is_dc_flow is true, this module adds the standard DC linearisation: for every connected zone pair (z1, z2) with a positive susceptance b[z1,z2], the net flow between the two zones is locked to the phase-angle difference times the susceptance:

\[\text{trans\_export}_{h,m,y,z_1,z_2} - \text{trans\_export}_{h,m,y,z_2,z_1} = b_{z_1,z_2} \cdot (\theta_{h,m,y,z_1} - \theta_{h,m,y,z_2}) \cdot \Delta h\]

The capacity bound on each direction (trans_export <= cap_lines_ existing) carries over unchanged, which means the thermal limit still applies but Kirchhoff is now enforced too. Loop flows on a multi-zone network are no longer free.

N-1 security-constrained mode (v1.18+)

When dc_parameters.is_n1_secure is also true and transmission_contingencies.csv lists which lines to protect against, the model is solved under a preventive security policy: the same gen decision must be feasible in the base case AND in every contingency where one listed line is out of service. For each contingency c, the module adds a parallel set of state variables (theta_c, trans_export_c) and constraints (DC flow with the outaged line forced to zero, capacity bounds, demand balance with contingency flows). gen and charge are NOT duplicated -- preventive policy means the same dispatch must work everywhere.

Inputs (all optional):

  • transmission_susceptance.csv -- columns zone1, zone2, value (one row per UNORDERED zone pair; the loader symmetrises to both directions). Units: MW per radian (so b * angle_diff is MW). Missing rows -> 0 (no constraint, equivalent to "no electrical connection between these zones").

  • transmission_contingencies.csv -- columns zone1, zone2, one line per contingency case. Each row removes the named line in one parallel solve. Empty file -> no contingencies, equivalent to is_n1_secure=false.

Config:

  • dc_parameters.is_dc_flow (bool, default false) -- enable/disable base-case DC flow.

  • dc_parameters.reference_zone (str, optional) -- zone whose phase angle is pinned to 0. Defaults to the first zone in model.zone.

  • dc_parameters.is_n1_secure (bool, default false) -- adds N-1 contingency constraints. Requires is_dc_flow=true.

The phase-angle variable model.theta is bounded to [-pi, pi] for numerical stability; in practice DC OPF angles stay well within +/- pi/2.

This module is LP-stable: no binaries, no new non-convexity.

class prepshot._model.dc_flow.AddDCFlowConstraints(model)[source]

Bases: object

DC linearised power-flow constraints, opt-in.

Parameters

model (object) --

cap_c_rule(h, m, y, z1, z2, c)[source]

Capacity bound on contingency-case flow.

trans_export_c[h, m, y, z1, z2, c] <= cap_lines_existing[y, z1, z2]. Same numeric bound as the base case -- gen is shared between base and contingency, so capacity stays consistent.

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

  • z1 (str) --

  • z2 (str) --

  • c (int) --

Return type

ConstraintIndex

demand_balance_c_rule(h, m, y, z, c)[source]

Power balance in contingency c.

Same as the base-case power_balance_rule in demand.py, but with contingency-case flows. gen and charge are the shared base-case decisions (preventive policy).

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

  • z (str) --

  • c (int) --

Return type

ConstraintIndex

flow_c_rule(h, m, y, z1, z2, c)[source]

Per-line DC flow eq in contingency c.

The outaged line self.contingencies[c] has its flow forced to zero (both directions). Every other line follows the same susceptance-times-angle-difference relation as the base case.

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

  • z1 (str) --

  • z2 (str) --

  • c (int) --

Return type

ConstraintIndex

flow_rule(h, m, y, z1, z2)[source]

Net flow = susceptance * angle difference * dt.

Only emitted for ordered pairs (z1, z2) with z1 < z2 and a positive susceptance, so each electrical line gets one constraint instead of two redundant ones. The capacity bound on each trans_export direction stays in place.

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

  • z1 (str) --

  • z2 (str) --

Return type

ConstraintIndex

theta_ref_c_rule(h, m, y, c)[source]

Pin reference zone's phase angle to 0 in contingency c.

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

  • c (int) --

Return type

ConstraintIndex

theta_ref_rule(h, m, y)[source]

Pin the reference zone's phase angle to 0.

Parameters
  • h (int) --

  • m (int) --

  • y (int) --

Return type

ConstraintIndex