Power Flow
PowerSystems.jl
provides the capability to run a power flow with the intention of providing a valid initial AC operating point to the system.
The power flow tool is not meant for analytics where the principal goal is to determine if the system has settings that produce a feasible AC solution. This power flow routine does not check for reactive power limits or other limiting mechanisms in the grid, and can therefore be used to check for solver convergence - making no guarantees of the solution feasibility.
The power flow solver uses NLsolve.jl under the hood and takes any keyword argument accepted by NLsolve. The solver uses the current operating point in the buses to provide the initial guess.
Limitations: The PowerFlow solver doesn't support systems with HVDC lines or Phase Shifting transformers yet. The power flow solver can't handle systems with islands.
Check section Power Flow for detailed usage instructions
using PowerSystems
const PSY = PowerSystems
system_data = System(joinpath(DATA_DIR, "matpower/case14.m"))
System
Base Power: 100.0
Components
Num components: 73
9 rows × 3 columns
ConcreteType | SuperTypes | Count | |
---|---|---|---|
String | String | Int64 | |
1 | Arc | Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 20 |
2 | Area | AggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
3 | Bus | Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 14 |
4 | FixedAdmittance | ElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
5 | Line | ACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 17 |
6 | LoadZone | AggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
7 | PowerLoad | StaticLoad <: ElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 11 |
8 | TapTransformer | ACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 3 |
9 | ThermalStandard | ThermalGen <: Generator <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 5 |
TimeSeriesContainer
Components with time series data: 0
Total StaticTimeSeries: 0
Total Forecasts: 0
Resolution: 0 seconds
PowerSystems.jl
has two modes of using the power flow solver.
Solving the power flow for the current operating point in the system. Takes the data in the buses, the
active_power
andreactive_power
fields in the static injection devices. Returns a dictionary with results in a DataFrame that can be exported or manipulated as needed.Solves the power flow and updated the devices in the system to the operating condition. This model will update the values of magnitudes and angles in the system's buses. It also updates the active and reactive power flows in the branches and devices connected to PV buses. It also updates the active and reactive power of the injection devices connected to the Slack bus, and updates only the reactive power of the injection devices connected to PV buses. If multiple devices are connected to the same bus, the power is divided proportional to the base power. This utility is useful to initialize systems before serializing or checking the addition of new devices is still AC feasible.
Solving the power flow with mode 1:
results = solve_powerflow(system_data)
results["bus_results"]
14 rows × 9 columns
bus_number | Vm | θ | P_gen | P_load | P_net | Q_gen | Q_load | Q_net | |
---|---|---|---|---|---|---|---|---|---|
Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
1 | 1 | 1.06 | 0.0 | 232.401 | 0.0 | 232.401 | -16.4453 | 0.0 | -16.4453 |
2 | 2 | 1.045 | -0.0869681 | 40.0 | 21.7 | 18.3 | 43.8949 | 12.7 | 31.1949 |
3 | 3 | 1.01 | -0.222121 | 0.0 | 94.2 | -94.2 | 25.2831 | 19.0 | 6.28314 |
4 | 4 | 1.01732 | -0.179889 | 0.0 | 47.8 | -47.8 | 0.0 | -3.9 | 3.9 |
5 | 5 | 1.01928 | -0.153111 | 0.0 | 7.6 | -7.6 | 0.0 | 1.6 | -1.6 |
6 | 6 | 1.07 | -0.248537 | 0.0 | 11.2 | -11.2 | 13.6279 | 7.5 | 6.12788 |
7 | 7 | 1.06039 | -0.232971 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
8 | 8 | 1.09 | -0.232971 | 0.0 | 0.0 | 0.0 | 18.3226 | 0.0 | 18.3226 |
9 | 9 | 1.05368 | -0.260528 | 0.0 | 29.5 | -29.5 | 0.0 | -2.4 | 2.4 |
10 | 10 | 1.04912 | -0.263386 | 0.0 | 9.0 | -9.0 | 0.0 | 5.8 | -5.8 |
11 | 11 | 1.05595 | -0.258232 | 0.0 | 3.5 | -3.5 | 0.0 | 1.8 | -1.8 |
12 | 12 | 1.05502 | -0.263446 | 0.0 | 6.1 | -6.1 | 0.0 | 1.6 | -1.6 |
13 | 13 | 1.05005 | -0.264781 | 0.0 | 13.5 | -13.5 | 0.0 | 5.8 | -5.8 |
14 | 14 | 1.03409 | -0.27988 | 0.0 | 14.9 | -14.9 | 0.0 | 5.0 | -5.0 |
Solving the power flow with mode 2:
Before running the power flow command these are the values of the voltages:
for b in get_components(Bus, system_data)
println("$(get_name(b)) - Magnitude $(get_magnitude(b)) - Angle (rad) $(get_angle(b))")
end
Bus 3 HV - Magnitude 1.01 - Angle (rad) -0.22200588085367873 Bus 11 LV - Magnitude 1.057 - Angle (rad) -0.2581341963699613 Bus 9 LV - Magnitude 1.056 - Angle (rad) -0.2607521902479528 Bus 1 HV - Magnitude 1.06 - Angle (rad) 0.0 Bus 13 LV - Magnitude 1.05 - Angle (rad) -0.2645919146023404 Bus 10 LV - Magnitude 1.051 - Angle (rad) -0.26354471705114374 Bus 7 ZV - Magnitude 1.062 - Angle (rad) -0.23335052099164186 Bus 8 TV - Magnitude 1.09 - Angle (rad) -0.2331759880664424 Bus 5 HV - Magnitude 1.02 - Angle (rad) -0.15323990832510212 Bus 14 LV - Magnitude 1.036 - Angle (rad) -0.27995081201989047 Bus 12 LV - Magnitude 1.055 - Angle (rad) -0.2630211182755455 Bus 6 LV - Magnitude 1.07 - Angle (rad) -0.24818581963359368 Bus 2 HV - Magnitude 1.045 - Angle (rad) -0.08691739674931762 Bus 4 HV - Magnitude 1.019 - Angle (rad) -0.18029251173101424
solve_powerflow!
return true or false to signal the successful result of the power flow. This enables the integration of a power flow into functions and use the return as check. For instance, initializing dynamic simulations. Also, because solve_powerflow!
uses NLsolve.jl all the parameters used for NLsolve are also available for solve_powerflow!
solve_powerflow!(system_data; finite_diff = true, method = :newton)
true
After running the power flow command this are the values of the voltages:
for b in get_components(Bus, system_data)
println("$(get_name(b)) - Magnitude $(get_magnitude(b)) - Angle (rad) $(get_angle(b))")
end
Bus 3 HV - Magnitude 1.01 - Angle (rad) -0.2221206 Bus 11 LV - Magnitude 1.055954 - Angle (rad) -0.2582317 Bus 9 LV - Magnitude 1.0536844 - Angle (rad) -0.2605284 Bus 1 HV - Magnitude 1.06 - Angle (rad) 0.0 Bus 13 LV - Magnitude 1.0500508 - Angle (rad) -0.2647811 Bus 10 LV - Magnitude 1.0491216 - Angle (rad) -0.2633861 Bus 7 ZV - Magnitude 1.0603896 - Angle (rad) -0.2329706 Bus 8 TV - Magnitude 1.09 - Angle (rad) -0.2329706 Bus 5 HV - Magnitude 1.0192849 - Angle (rad) -0.1531107 Bus 14 LV - Magnitude 1.0340927 - Angle (rad) -0.2798801 Bus 12 LV - Magnitude 1.055018 - Angle (rad) -0.2634456 Bus 6 LV - Magnitude 1.07 - Angle (rad) -0.2485369 Bus 2 HV - Magnitude 1.045 - Angle (rad) -0.0869681 Bus 4 HV - Magnitude 1.0173242 - Angle (rad) -0.1798885