Optimal transmission switching

Optimal Transmission Switching decides the on/off state of network elements so as to minimize generation cost. Counter-intuitively, removing a line can reduce cost: it redistributes power flows away from congested corridors, letting cheaper generation dispatch that would otherwise be constrained off.

Each switchable element carries a binary variable equal to 1 when energized and 0 when disconnected. The package provides three problem specifications, differing only in which elements get one.

Problem specifications

run_acdcots_AC(data, model_type, solver; kwargs...)
run_acdcots_DC(data, model_type, solver; kwargs...)
run_acdcots_AC_DC(data, model_type, solver; kwargs...)
FunctionAC branchesDC branchesAC/DC converters
run_acdcots_AC✅——
run_acdcots_DC—✅✅
run_acdcots_AC_DC✅✅✅
# from a Dict (preferred — you usually want to inspect or modify the data first)
data = _PM.parse_file("case5_acdc.m")
_PMACDC.process_additional_data!(data)
result = _PMTP.run_acdcots_AC(data, ACPPowerModel, juniper; setting = s)

# from a path (parses and calls process_additional_data! for you)
result = _PMTP.run_acdcots_AC("case5_acdc.m", ACPPowerModel, juniper; setting = s)

What each model builds

run_acdcots_AC

Adds _PM.variable_branch_indicator — one binary z_ac per AC branch — and swaps the AC branch constraints for their on/off counterparts:

  • Ohm's law from/to (constraint_ohms_yt_*_on_off)
  • voltage angle difference (constraint_voltage_angle_difference_on_off)
  • thermal limits from/to (constraint_thermal_limit_*_on_off)

Bus voltages use variable_bus_voltage_on_off, which relaxes voltage bounds on buses that may become islanded. The DC grid is modelled exactly as in a standard AC/DC OPF.

run_acdcots_DC

Adds variable_dc_branch_indicator (z_dc, one per DC branch), variable_dc_conv_indicator (z_cv, one per converter), and a voltage slack variable. The corresponding constraints are all package-local:

ConstraintPurpose
constraint_ohms_ots_dc_branchDC Ohm's law, deactivated when z_dc = 0
constraint_branch_limit_on_off_dc_otsforces DC branch flow to zero when open
constraint_converter_losses_dc_otsconverter loss curve, zeroed when z_cv = 0
constraint_converter_current_otsconverter current, zeroed when z_cv = 0
constraint_conv_transformer_dc_otsconverter transformer
constraint_conv_reactor_dc_otsconverter phase reactor
constraint_converter_limit_on_off_dc_otszeroes AC- and DC-side converter power

The pairing of the loss and current constraints is what guarantees that a de-energized converter contributes exactly zero losses, rather than the constant term a_cv of its loss curve. This matters: without it the model would pay standby losses for equipment it has switched off.

run_acdcots_AC_DC

The union of the two. Binaries on AC branches, DC branches, and converters, all optimized in one problem.

Reading the results

Switching decisions are reported into the standard PowerModels solution dictionary:

ElementPathKey
AC branchresult["solution"]["branch"][id]br_status
DC branchresult["solution"]["branchdc"][id]br_status
Converterresult["solution"]["convdc"][id]conv_status
opened = [id for (id, br) in result["solution"]["branch"] if br["br_status"] < 0.1]
println("de-energized AC branches: ", opened)

Restricting which elements may switch

The models make every branch and converter switchable by default. This is convenient for small studies and untenable for anything else — binary count is often what drives the computational complexity of the problem and its solve time, and in a real network most lines cannot be arbitrarily de-energized anyway.

There is no built-in API for selecting a subset. A practical workaround is to fix the binaries you do not want free, via PowerModels' variable start/bound machinery, or by pre-filtering the data. Fixing all the binaries reduces the problem to a conventional OPF for hybrid AC/DC grids, which is a useful sanity check that your setup is correct.

Automatic selection of the most promising lines is listed as future work in the reference paper. The literature it points to for line-ranking heuristics, e.g. LMP-difference screening, sensitivity analysis, congestion-zone identification, is a reasonable starting point if you need to build this yourself.

Formulation support

OTS is implemented for the exact non-convex formulation only. Relaxations and linear approximations are available for busbar splitting, not for OTS.

result = run_acdcots_AC_DC(data, ACPPowerModel, juniper; setting = s)   # ✅
result = run_acdcots_AC_DC(data, LPACCPowerModel, gurobi; setting = s)  # ✗ not supported

The rationale is that the paper's contribution is the BuS model; the same relaxation strategy would apply to OTS, but it has not been implemented or validated here.

Caveat: protection

The model tells you that a topology is cheaper. It does not tell you that it is safe to operate. Coordination between the elements selected for switching and the grid's protection strategy has to be verified separately, at the planning stage, before any of these actions would be used in practice during grid operations.