diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 5c2bbf20..5fd998be 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-08T12:26:59","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-08T12:44:08","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/dev/api/analysis/index.html b/dev/api/analysis/index.html index 7e905419..706beaa3 100644 --- a/dev/api/analysis/index.html +++ b/dev/api/analysis/index.html @@ -10,7 +10,7 @@ end solve!(system, analysis) end -power!(system, analysis)source
JuliaGrid.injectionPowerMethod
injectionPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power injections associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
+power!(system, analysis)
source
JuliaGrid.injectionPowerMethod
injectionPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power injections associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -21,7 +21,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = injectionPower(system, analysis; label = 1)
source
JuliaGrid.supplyPowerMethod
supplyPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power injections from the generators associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
+active, reactive = injectionPower(system, analysis; label = 1)
source
JuliaGrid.supplyPowerMethod
supplyPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power injections from the generators associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -32,7 +32,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = supplyPower(system, analysis; label = 1)
source
JuliaGrid.shuntPowerMethod
shuntPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power values of the shunt element associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
+active, reactive = supplyPower(system, analysis; label = 1)
source
JuliaGrid.shuntPowerMethod
shuntPower(system::PowerSystem, analysis::AC, label)

The function returns the active and reactive power values of the shunt element associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -43,7 +43,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = shuntPower(system, analysis; label = 9)

```

source
JuliaGrid.fromPowerMethod
fromPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power flows at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
+active, reactive = shuntPower(system, analysis; label = 9)

```

source
JuliaGrid.fromPowerMethod
fromPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power flows at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -54,7 +54,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = fromPower(system, analysis; label = 2)
source
JuliaGrid.toPowerMethod
toPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power flows at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
+active, reactive = fromPower(system, analysis; label = 2)
source
JuliaGrid.toPowerMethod
toPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power flows at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -65,7 +65,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = toPower(system, analysis; label = 2)
source
JuliaGrid.seriesPowerMethod
seriesPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power losses across the series impedance of a specific branch within the AC framework. The label keyword argument should correspond to an existing branch label.

Example

system = powerSystem("case14.h5")
+active, reactive = toPower(system, analysis; label = 2)
source
JuliaGrid.seriesPowerMethod
seriesPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power losses across the series impedance of a specific branch within the AC framework. The label keyword argument should correspond to an existing branch label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -76,7 +76,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = seriesPower(system, analysis; label = 2)
source
JuliaGrid.chargingPowerMethod
chargingPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power values associated with the charging admittances of a specific branch in the AC framework. The label keyword argument must correspond to an existing branch label.

Example

system = powerSystem("case14.h5")
+active, reactive = seriesPower(system, analysis; label = 2)
source
JuliaGrid.chargingPowerMethod
chargingPower(system::PowerSystem, analysis::AC; label)

The function returns the active and reactive power values associated with the charging admittances of a specific branch in the AC framework. The label keyword argument must correspond to an existing branch label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -87,7 +87,7 @@
     end
     solve!(system, analysis)
 end
-active, reactive = chargingPower(system, analysis; label = 2)
source
JuliaGrid.generatorPowerMethod
generatorPower(system::PowerSystem, analysis::AC)

The function returns the active and reactive powers associated with a specific generator in the AC framework. The label keyword argument must match an existing generator label.

Example

system = powerSystem("case14.h5")
+active, reactive = chargingPower(system, analysis; label = 2)
source
JuliaGrid.generatorPowerMethod
generatorPower(system::PowerSystem, analysis::AC)

The function returns the active and reactive powers associated with a specific generator in the AC framework. The label keyword argument must match an existing generator label.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -98,69 +98,69 @@
     end
     solve!(system, analysis)
 end
-active, reactive = generatorPower(system, analysis; label = 1)
source

AC Current Analysis

JuliaGrid.current!Method
current!(system::PowerSystem, analysis::AC)

The function computes the currents in the polar coordinate system associated with buses and branches in the AC framework.

Updates

This function calculates various electrical quantities in the polar coordinate system:

  • injection: Current injections at each bus.
  • from: Current flows at each from-bus end of the branch.
  • to: Current flows at each to-bus end of the branch.
  • series: Current flows through the series impedance of the branch in the direction from the from-bus end to the to-bus end of the branch.

Example

using Ipopt
+active, reactive = generatorPower(system, analysis; label = 1)
source

AC Current Analysis

JuliaGrid.current!Method
current!(system::PowerSystem, analysis::AC)

The function computes the currents in the polar coordinate system associated with buses and branches in the AC framework.

Updates

This function calculates various electrical quantities in the polar coordinate system:

  • injection: Current injections at each bus.
  • from: Current flows at each from-bus end of the branch.
  • to: Current flows at each to-bus end of the branch.
  • series: Current flows through the series impedance of the branch in the direction from the from-bus end to the to-bus end of the branch.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
 solve!(system, analysis)
-current!(system, analysis)
source
JuliaGrid.injectionCurrentMethod
injectionCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current injection in the polar coordinate system associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

using Ipopt
+current!(system, analysis)
source
JuliaGrid.injectionCurrentMethod
injectionCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current injection in the polar coordinate system associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
 solve!(system, analysis)
-magnitude, angle = injectionCurrent(system, analysis; label = 1)
source
JuliaGrid.fromCurrentMethod
fromCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
+magnitude, angle = injectionCurrent(system, analysis; label = 1)
source
JuliaGrid.fromCurrentMethod
fromCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
 solve!(system, analysis)
-magnitude, angle = fromCurrent(system, analysis; label = 2)
source
JuliaGrid.toCurrentMethod
toCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
+magnitude, angle = fromCurrent(system, analysis; label = 2)
source
JuliaGrid.toCurrentMethod
toCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
 solve!(system, analysis)
-magnitude, angle = toCurrent(system, analysis; label = 2)
source
JuliaGrid.seriesCurrentMethod
seriesCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system through series impedance associated with a specific branch in the direction from the from-bus end to the to-bus end of the branch within the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
+magnitude, angle = toCurrent(system, analysis; label = 2)
source
JuliaGrid.seriesCurrentMethod
seriesCurrent(system::PowerSystem, analysis::AC; label)

The function returns the current in the polar coordinate system through series impedance associated with a specific branch in the direction from the from-bus end to the to-bus end of the branch within the AC framework. The label keyword argument must match an existing branch label.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
 solve!(system, analysis)
-magnitude, angle = seriesCurrent(system, analysis; label = 2)
source

DC Power Analysis

JuliaGrid.power!Method
power!(system::PowerSystem, analysis::DC)

The function calculates the active power values related to buses, branches, and generators within the DC analysis framework.

Updates

This function updates the power field of the DC abstract type by computing the following electrical quantities:

  • injection: Active power injections at each bus.
  • supply: Active power injections from the generators at each bus.
  • from: Active power flows at each from-bus end of the branch.
  • to: Active power flows at each to-bus end of the branch.
  • generator: Output active powers of each generator (excluding for state estimation).

Example

system = powerSystem("case14.h5")
+magnitude, angle = seriesCurrent(system, analysis; label = 2)
source

DC Power Analysis

JuliaGrid.power!Method
power!(system::PowerSystem, analysis::DC)

The function calculates the active power values related to buses, branches, and generators within the DC analysis framework.

Updates

This function updates the power field of the DC abstract type by computing the following electrical quantities:

  • injection: Active power injections at each bus.
  • supply: Active power injections from the generators at each bus.
  • from: Active power flows at each from-bus end of the branch.
  • to: Active power flows at each to-bus end of the branch.
  • generator: Output active powers of each generator (excluding for state estimation).

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-power!(system, analysis)
source
JuliaGrid.injectionPowerMethod
injectionPower(system::PowerSystem, analysis::DC; label)

The function returns the active power injection associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
+power!(system, analysis)
source
JuliaGrid.injectionPowerMethod
injectionPower(system::PowerSystem, analysis::DC; label)

The function returns the active power injection associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-injection = injectionPower(system, analysis; label = 2)
source
JuliaGrid.supplyPowerMethod
supplyPower(system::PowerSystem, analysis::DC; label)

The function returns the active power injection from the generators associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
+injection = injectionPower(system, analysis; label = 2)
source
JuliaGrid.supplyPowerMethod
supplyPower(system::PowerSystem, analysis::DC; label)

The function returns the active power injection from the generators associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-supply = supplyPower(system, analysis; label = 2)
source
JuliaGrid.fromPowerMethod
fromPower(system::PowerSystem, analysis::DC; label)

The function returns the active power flow at the from-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
+supply = supplyPower(system, analysis; label = 2)
source
JuliaGrid.fromPowerMethod
fromPower(system::PowerSystem, analysis::DC; label)

The function returns the active power flow at the from-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-from = fromPower(system, analysis; label = 2)
source
JuliaGrid.toPowerMethod
toPower(system::PowerSystem, analysis::DC; label)

The function returns the active power flow at the to-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
+from = fromPower(system, analysis; label = 2)
source
JuliaGrid.toPowerMethod
toPower(system::PowerSystem, analysis::DC; label)

The function returns the active power flow at the to-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-to = toPower(system, analysis; label = 2)
source
JuliaGrid.generatorPowerMethod
generatorPower(system::PowerSystem, analysis::DC; label)

This function returns the output active power associated with a specific generator in the DC framework. The label keyword argument must match an existing generator label.

Example

system = powerSystem("case14.h5")
+to = toPower(system, analysis; label = 2)
source
JuliaGrid.generatorPowerMethod
generatorPower(system::PowerSystem, analysis::DC; label)

This function returns the output active power associated with a specific generator in the DC framework. The label keyword argument must match an existing generator label.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
 solve!(system, analysis)
-generator = generatorPower(system, analysis; label = 1)
source
+generator = generatorPower(system, analysis; label = 1)source diff --git a/dev/api/measurementModel/index.html b/dev/api/measurementModel/index.html index 6a51f588..a530fb9e 100644 --- a/dev/api/measurementModel/index.html +++ b/dev/api/measurementModel/index.html @@ -1,5 +1,5 @@ -Measurement Model · JuliaGrid

Measurement Model

For further information on this topic, please see the Measurement Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate with measurement devices.

To load measurement model API functionalities into the current scope, utilize the following command:

using JuliaGrid

Measurement Data
Voltmeter
Ammeter
Wattmeter
Varmeter
PMU

Measurement Data

JuliaGrid.measurementFunction
measurement(file::String)

The function builds the composite type Measurement and populates voltmeter, ammeter, wattmeter, varmeter, and pmu fields. In general, once the composite type Measurement has been created, it is possible to add new measurement devices, or modify the parameters of existing ones.

Argument

It requires a string path to the HDF5 file with the .h5 extension.

Returns

The Measurement composite type with the following fields:

  • voltmeter: Bus voltage magnitude measurements.
  • ammeter: Branch current magnitude measurements.
  • wattmeter: Active power injection and active power flow measurements.
  • varmeter: Reactive power injection and reactive power flow measurements.
  • pmu: Bus voltage and branch current phasor measurements.

Units

JuliaGrid stores all data in per-units and radians format.

Example

device = measurement("measurement14.h5")
source
measurement()

Alternatively, the Measurement composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed.

Example

device = measurement()
source
JuliaGrid.saveMeasurementFunction
saveMeasurement(device::Measurement; path::String, reference::String, note::String)

The function saves the measurement's data in the HDF5 file using the fields voltmeter, ammeter, wattmeter, varmeter, and pmu from the Measurement composite type.

Keywords

The location and file name of the HDF5 file is specified by the mandatory keyword path in the format of "path/name.h5". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.

View HDF5 File

To view the saved HDF5 file, you can use the HDFView software.

Example

using Ipopt
+Measurement Model · JuliaGrid

Measurement Model

For further information on this topic, please see the Measurement Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate with measurement devices.

To load measurement model API functionalities into the current scope, utilize the following command:

using JuliaGrid

Measurement Data
Voltmeter
Ammeter
Wattmeter
Varmeter
PMU

Measurement Data

JuliaGrid.measurementFunction
measurement(file::String)

The function builds the composite type Measurement and populates voltmeter, ammeter, wattmeter, varmeter, and pmu fields. In general, once the composite type Measurement has been created, it is possible to add new measurement devices, or modify the parameters of existing ones.

Argument

It requires a string path to the HDF5 file with the .h5 extension.

Returns

The Measurement composite type with the following fields:

  • voltmeter: Bus voltage magnitude measurements.
  • ammeter: Branch current magnitude measurements.
  • wattmeter: Active power injection and active power flow measurements.
  • varmeter: Reactive power injection and reactive power flow measurements.
  • pmu: Bus voltage and branch current phasor measurements.

Units

JuliaGrid stores all data in per-units and radians format.

Example

device = measurement("measurement14.h5")
source
measurement()

Alternatively, the Measurement composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed.

Example

device = measurement()
source
JuliaGrid.saveMeasurementFunction
saveMeasurement(device::Measurement; path::String, reference::String, note::String)

The function saves the measurement's data in the HDF5 file using the fields voltmeter, ammeter, wattmeter, varmeter, and pmu from the Measurement composite type.

Keywords

The location and file name of the HDF5 file is specified by the mandatory keyword path in the format of "path/name.h5". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.

View HDF5 File

To view the saved HDF5 file, you can use the HDFView software.

Example

using Ipopt
 
 system = powerSystem("case14.m")
 device = measurement()
@@ -12,7 +12,7 @@
 addVoltmeter!(system, device, analysis)
 addWattmeter!(system, device, analysis)
 
-saveMeasurement(device; path = "D:/measurement14.h5")
source
JuliaGrid.status!Function
status!(system::PowerSystem, device::Measurement; inservice, outservice, redundancy)

The function generates a set of measurements, assigning measurement devices randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Only one of the following keywords can be used at a time to configure the measurement set:

  • inservice: Sets the number of in-service devices.
  • outservice: Sets the number of out-of-service devices.
  • redundancy: Determines in-service devices based on redundancy.

Updates

The function updates all the status fields within the Measurement type.

Examples

Creating a measurement set with a specific number of in-service devices:

system = powerSystem("case14.h5")
+saveMeasurement(device; path = "D:/measurement14.h5")
source
JuliaGrid.status!Function
status!(system::PowerSystem, device::Measurement; inservice, outservice, redundancy)

The function generates a set of measurements, assigning measurement devices randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Only one of the following keywords can be used at a time to configure the measurement set:

  • inservice: Sets the number of in-service devices.
  • outservice: Sets the number of out-of-service devices.
  • redundancy: Determines in-service devices based on redundancy.

Updates

The function updates all the status fields within the Measurement type.

Examples

Creating a measurement set with a specific number of in-service devices:

system = powerSystem("case14.h5")
 device = measurement()
 
 acModel!(system)
@@ -47,7 +47,7 @@
 addWattmeter!(system, device, analysis)
 addVarmeter!(system, device, analysis)
 
-status!(system, device; redundancy = 2.5)
source

Voltmeter

JuliaGrid.addVoltmeter!Method
addVoltmeter!(system::PowerSystem, device::Measurement; label, bus, magnitude, variance,
+status!(system, device; redundancy = 2.5)
source

Voltmeter

JuliaGrid.addVoltmeter!Method
addVoltmeter!(system::PowerSystem, device::Measurement; label, bus, magnitude, variance,
     noise, status)

The function adds a new voltmeter that measures bus voltage magnitude to the Measurement type within a given PowerSystem type. The voltmeter can be added to an already defined bus.

Keywords

The voltmeter is defined with the following keywords:

  • label: Unique label for the voltmeter.
  • bus: Label of the bus to which the voltmeter is connected.
  • magnitude (pu or V): Bus voltage magnitude value.
  • variance (pu or V): Variance of the bus voltage magnitude measurement.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the magnitude,
    • noise = false: uses the magnitude value only.
  • status: Operating status of the voltmeter:
    • status = 1: in-service,
    • status = 0: out-of-service.

Updates

The function updates the voltmeter field of the Measurement composite type.

Default Settings

Default settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, and users can modify these default settings using the @voltmeter macro.

Units

The default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.

Examples

Adding a voltmeter using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -59,7 +59,7 @@
 
 addBus!(system; label = "Bus 1", base = 132.0)
 
-addVoltmeter!(system, device; label = "Voltmeter 1", bus = "Bus 1", magnitude = 145.2)
source
JuliaGrid.addVoltmeter!Method
addVoltmeter!(system::PowerSystem, device::Measurement, analysis::AC; variance, noise,
+addVoltmeter!(system, device; label = "Voltmeter 1", bus = "Bus 1", magnitude = 145.2)
source
JuliaGrid.addVoltmeter!Method
addVoltmeter!(system::PowerSystem, device::Measurement, analysis::AC; variance, noise,
     status)

The function incorporates voltmeters into the Measurement composite type for every bus within the PowerSystem type. These measurements are derived from the exact bus voltage magnitudes defined in the AC type.

Keywords

Users have the option to configure the following keywords:

  • variance (pu or V): Variance of bus voltage magnitude measurements.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the voltage magnitudes,
    • noise = false: uses the exact voltage magnitude values.
  • status: Operating status of the voltmeters:
    • status = 1: in-service,
    • status = 0: out-of-service.

Updates

The function updates the voltmeter field of the Measurement composite type.

Default Settings

Default settings for keywords are as follows: variance = 1e-2, noise = false, and status = 1, and users can modify these default settings using the @voltmeter macro.

Units

By default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.

Example

system = powerSystem("case14.h5")
 device = measurement()
 
@@ -74,14 +74,14 @@
 end
 
 @voltmeter(label = "Voltmeter ?")
-addVoltmeter!(system, device, analysis; variance = 1e-3, noise = true)
source
JuliaGrid.updateVoltmeter!Function
updateVoltmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
+addVoltmeter!(system, device, analysis; variance = 1e-3, noise = true)
source
JuliaGrid.updateVoltmeter!Function
updateVoltmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
     kwargs...)

The function allows for the alteration of parameters for a voltmeter.

Arguments

If the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific voltmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVoltmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing voltmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the voltmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addVoltmeter! function.

Example

system = powerSystem()
 device = measurement()
 
 addBus!(system; label = "Bus 1", base = 132e3)
 
 addVoltmeter!(system, device; label = "Voltmeter 1", bus = "Bus 1", magnitude = 1.1)
-updateVoltmeter!(system, device; label = "Voltmeter 1", magnitude = 0.9)
source
JuliaGrid.statusVoltmeter!Function
statusVoltmeter!(system::PowerSystem, device::Measurement; inservice, outservice,
+updateVoltmeter!(system, device; label = "Voltmeter 1", magnitude = 0.9)
source
JuliaGrid.statusVoltmeter!Function
statusVoltmeter!(system::PowerSystem, device::Measurement; inservice, outservice,
     redundancy)

The function generates a set of voltmeters, assigning voltmeters randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Only one of the following keywords can be used at a time to configure the measurement set:

  • inservice: Sets the number of in-service voltmeters.
  • outservice: Sets the number of out-of-service voltmeters.
  • redundancy: Determines in-service voltmeters based on redundancy.

Updates

The function updates the status field within the Voltmeter type.

Example

system = powerSystem("case14.h5")
 device = measurement()
 
@@ -96,7 +96,7 @@
 end
 
 addVoltmeter!(system, device, analysis)
-statusVoltmeter!(system, device; inservice = 10)
source
JuliaGrid.@voltmeterMacro
@voltmeter(label, variance, noise, status)

The macro generates a template for a voltmeter, which can be utilized to define a voltmeter using the addVoltmeter! function.

Keywords

To establish the voltmeter template, users can specify default values for the variance, noise, and status keywords, along with pattern for labels using the label keyword.

Units

By default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.

Examples

Adding a voltmeter using the default unit system:

system = powerSystem()
+statusVoltmeter!(system, device; inservice = 10)
source
JuliaGrid.@voltmeterMacro
@voltmeter(label, variance, noise, status)

The macro generates a template for a voltmeter, which can be utilized to define a voltmeter using the addVoltmeter! function.

Keywords

To establish the voltmeter template, users can specify default values for the variance, noise, and status keywords, along with pattern for labels using the label keyword.

Units

By default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.

Examples

Adding a voltmeter using the default unit system:

system = powerSystem()
 device = measurement()
 
 addBus!(system; label = "Bus 1", base = 132e3)
@@ -109,7 +109,7 @@
 addBus!(system; label = "Bus 1", base = 132.0)
 
 @voltmeter(label = "Voltmeter ?", variance = 0.00132)
-addVoltmeter!(system, device; bus = "Bus 1", magnitude = 145.2)
source

Ammeter

JuliaGrid.addAmmeter!Method
addAmmeter!(system::PowerSystem, device::Measurement; label, from, to, magnitude,
+addVoltmeter!(system, device; bus = "Bus 1", magnitude = 145.2)
source

Ammeter

JuliaGrid.addAmmeter!Method
addAmmeter!(system::PowerSystem, device::Measurement; label, from, to, magnitude,
     variance, noise, status)

The function adds a new ammeter that measures branch current magnitude to the Measurement type within a given PowerSystem type. The ammeter can be added to an already defined branch.

Keywords

The ammeter is defined with the following keywords:

  • label: Unique label for the ammeter.
  • from: Label of the branch if the ammeter is located at the from-bus end.
  • to: Label of the branch if the ammeter is located at the to-bus end.
  • magnitude (pu or A): Branch current magnitude value.
  • variance (pu or A): Variance of the branch current magnitude measurement.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the magnitude,
    • noise = false: uses the magnitude value only.
  • status: Operating status of the ammeter:
    • status = 1: in-service,
    • status = 0: out-of-service.

Updates

The function updates the ammeter field of the Measurement composite type.

Default Settings

Default settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, which apply to ammeters located at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for ammeters positioned on either the from-bus or to-bus ends of branches using the @ammeter macro.

Units

The default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.

Examples

Adding ammeters using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -127,7 +127,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addAmmeter!(system, device; label = "Ammeter 1", from = "Branch 1", magnitude = 481.125)
-addAmmeter!(system, device; label = "Ammeter 2", to = "Branch 1", magnitude = 437.386)
source
JuliaGrid.addAmmeter!Method
addAmmeter!(system::PowerSystem, device::Measurement, analysis::AC; varianceFrom,
+addAmmeter!(system, device; label = "Ammeter 2", to = "Branch 1", magnitude = 437.386)
source
JuliaGrid.addAmmeter!Method
addAmmeter!(system::PowerSystem, device::Measurement, analysis::AC; varianceFrom,
     statusFrom, varianceTo, statusTo, noise)

The function incorporates ammeters into the Measurement type for every branch within the PowerSystem type. These measurements are derived from the exact branch current magnitudes defined in the AC type.

Keywords

Users have the option to configure the following keywords:

  • varianceFrom (pu or A): Measurement variance for ammeters at the from-bus ends.
  • statusFrom: Operating status of the ammeters at the from-bus ends:
    • statusFrom = 1: in-service,
    • statusFrom = 0: out-of-service.
  • varianceTo (pu or A): Measurement variance for ammeters at the to-bus ends.
  • statusTo: Operating status of the ammeters at the to-bus ends:
    • statusTo = 1: in-service,
    • statusTo = 0: out-of-service.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the current magnitudes,
    • noise = false: uses the exact current magnitude values.

Updates

The function updates the ammeter field of the Measurement composite type.

Default Settings

Default settings for keywords are as follows: varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @ammeter macro.

Units

The default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.

Example

system = powerSystem("case14.h5")
 device = measurement()
 
@@ -143,7 +143,7 @@
 current!(system, analysis)
 
 @ammeter(label = "Ammeter ?")
-addAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0)
source
JuliaGrid.updateAmmeter!Function
updateAmmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
+addAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0)
source
JuliaGrid.updateAmmeter!Function
updateAmmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
     kwargs...)

The function allows for the alteration of parameters for an ammeter.

Arguments

If the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific ammeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addAmmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing ammeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the ammeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addAmmeter! function.

Example

system = powerSystem()
 device = measurement()
 
@@ -152,7 +152,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addAmmeter!(system, device; label = "Ammeter 1", from = "Branch 1", magnitude = 1.1)
-updateAmmeter!(system, device; label = "Ammeter 1", magnitude = 1.2, variance = 1e-4)
source
JuliaGrid.statusAmmeter!Function
statusAmmeter!(system::PowerSystem, ammeter::Ammeter; inservice, inserviceFrom,
+updateAmmeter!(system, device; label = "Ammeter 1", magnitude = 1.2, variance = 1e-4)
source
JuliaGrid.statusAmmeter!Function
statusAmmeter!(system::PowerSystem, ammeter::Ammeter; inservice, inserviceFrom,
     inserviceTo, outservice, outserviceFrom, outserviceTo, redundancy, redundancyFrom,
     redundancyTo)

The function generates a set of ammeters, assigning ammeters randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Users may use either one main keyword or two fine-tuning keywords that specify distinct locations per function call:

  • inservice: Sets the number of in-service ammeters or allows fine-tuning:
    • inserviceFrom: sets only ammeters loacted at the from-bus end,
    • inserviceTo: sets only ammeters loacted at the to-bus end.
  • outservice: Sets the number of out-of-service ammeters or allows fine-tuning:
    • outserviceFrom: sets only ammeters loacted at the from-bus end,
    • outserviceTo: sets only ammeters loacted at the to-bus end.
  • redundancy: Determines in-service ammeters based on redundancy or allows fine-tuning:
    • redundancyFrom: determines only ammeters loacted at the from-bus end,
    • redundancyTo: determines only ammeters loacted at the to-bus end.

Updates

The function updates the status field within the Ammeter type.

Example

system = powerSystem("case14.h5")
 device = measurement()
@@ -169,7 +169,7 @@
 current!(system, analysis)
 
 addAmmeter!(system, device, analysis)
-statusAmmeter!(system, device; inserviceFrom = 5, inserviceTo = 10)
source
JuliaGrid.@ammeterMacro
@ammeter(label, varianceFrom, statusFrom, varianceTo, statusTo, noise)

The macro generates a template for an ammeter, which can be utilized to define an ammeter using the addAmmeter! function.

Keywords

To establish the ammeter template, users can set default variance and status values for ammeters at both the from-bus and to-bus ends of branches, using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.

Units

The default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.

Examples

Adding an ammeter using the default unit system:

system = powerSystem()
+statusAmmeter!(system, device; inserviceFrom = 5, inserviceTo = 10)
source
JuliaGrid.@ammeterMacro
@ammeter(label, varianceFrom, statusFrom, varianceTo, statusTo, noise)

The macro generates a template for an ammeter, which can be utilized to define an ammeter using the addAmmeter! function.

Keywords

To establish the ammeter template, users can set default variance and status values for ammeters at both the from-bus and to-bus ends of branches, using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.

Units

The default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.

Examples

Adding an ammeter using the default unit system:

system = powerSystem()
 device = measurement()
 
 addBus!(system; label = "Bus 1", base = 132e3)
@@ -186,7 +186,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 @ammeter(label = "Ammeter ?", varianceTo = 0.004374, statusTo = 0)
-addAmmeter!(system, device; label = "Ammeter 1", to = "Branch 1", magnitude = 481.125)
source

Wattmeter

JuliaGrid.addWattmeter!Method
addWattmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, active,
+addAmmeter!(system, device; label = "Ammeter 1", to = "Branch 1", magnitude = 481.125)
source

Wattmeter

JuliaGrid.addWattmeter!Method
addWattmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, active,
     variance, noise, status)

The function adds a new wattmeter that measures active power injection or active power flow to the Measurement type within a given PowerSystem type. The wattmeter can be added to an already defined bus or branch.

Keywords

The wattmeter is defined with the following keywords:

  • label: Unique label for the wattmeter.
  • bus: Label of the bus if the wattmeter is located at the bus.
  • from: Label of the branch if the wattmeter is located at the from-bus end.
  • to: Label of the branch if the wattmeter is located at the to-bus end.
  • active (pu or W): Active power value.
  • variance (pu or W): Variance of the active power measurement.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the active,
    • noise = false: uses the active value only.
  • status: Operating status of the wattmeter:
    • status = 1: in-service,
    • status = 0: out-of-service.

Updates

The function updates the wattmeter field of the Measurement composite type.

Default Settings

Default settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to wattmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for wattmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @wattmeter macro.

Units

The default units for the active and variance keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.

Examples

Adding wattmeters using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -204,7 +204,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addWattmeter!(system, device; label = "Wattmeter 1", bus = "Bus 2", active = 40.0)
-addWattmeter!(system, device; label = "Wattmeter 2", from = "Branch 1", active = 10.0)
source
JuliaGrid.addWattmeter!Method
addWattmeter!(system::PowerSystem, device::Measurement, analysis::AC;
+addWattmeter!(system, device; label = "Wattmeter 2", from = "Branch 1", active = 10.0)
source
JuliaGrid.addWattmeter!Method
addWattmeter!(system::PowerSystem, device::Measurement, analysis::AC;
     varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)

The function incorporates wattmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact active power injections at buses and active power flows in branches defined in the AC type.

Keywords

Users have the option to configure the following keywords:

  • varianceBus (pu or W): Measurement variance for wattmeters at the buses.
  • statusBus: Operating status of the wattmeters at the buses:
    • statusBus = 1: in-service,
    • statusBus = 0: out-of-service.
  • varianceFrom (pu or W): Measurement variance for wattmeters at the from-bus ends.
  • statusFrom: Operating status of the wattmeters at the from-bus ends:
    • statusFrom = 1: in-service,
    • statusFrom = 0: out-of-service.
  • varianceTo (pu or W): Measurement variance for wattmeters at the to-bus ends.
  • statusTo: Operating status of the wattmeters at the to-bus ends:
    • statusTo = 1: in-service,
    • statusTo = 0: out-of-service.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the active powers,
    • noise = false: uses the exact active power values.

Updates

The function updates the wattmeter field of the Measurement composite type.

Default Settings

Default settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @wattmeter macro.

Units

The default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.

Example

system = powerSystem("case14.h5")
 device = measurement()
 
@@ -220,7 +220,7 @@
 power!(system, analysis)
 
 @wattmeter(label = "Wattmeter ?")
-addWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)
source
JuliaGrid.updateWattmeter!Function
updateWattmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
+addWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)
source
JuliaGrid.updateWattmeter!Function
updateWattmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
     kwargs...)

The function allows for the alteration of parameters for a wattmeter.

Arguments

If the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific wattmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addWattmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing wattmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the wattmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addWattmeter! function.

Example

system = powerSystem()
 device = measurement()
 
@@ -229,7 +229,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addWattmeter!(system, device; label = "Wattmeter 1", from = "Branch 1", active = 1.1)
-updateWattmeter!(system, device; label = "Wattmeter 1", active = 1.2, variance = 1e-4)
source
JuliaGrid.statusWattmeter!Function
statusWattmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
+updateWattmeter!(system, device; label = "Wattmeter 1", active = 1.2, variance = 1e-4)
source
JuliaGrid.statusWattmeter!Function
statusWattmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
     inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,
     redundancy, redundancyBus, redundancyFrom, redundancyTo)

The function generates a set of wattmeters, assigning wattmeters randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Users may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:

  • inservice: Sets the number of in-service wattmeters or allows fine-tuning:
    • inserviceBus: sets only wattmeters loacted at the bus,
    • inserviceFrom: sets only wattmeters loacted at the from-bus end,
    • inserviceTo: sets only wattmeters loacted at the to-bus end.
  • outservice: Sets the number of out-of-service wattmeters or allows fine-tuning:
    • outserviceBus: sets only wattmeters loacted at the bus,
    • outserviceFrom: sets only wattmeters loacted at the from-bus end,
    • outserviceTo: sets only wattmeters loacted at the to-bus end.
  • redundancy: Determines in-service wattmeters based on redundancy or allows fine-tuning:
    • redundancyBus: determines only wattmeters loacted at the bus,
    • redundancyFrom: determines only wattmeters loacted at the from-bus end,
    • redundancyTo: determines only wattmeters loacted at the to-bus end.

Updates

The function updates the status field within the Wattmeter type.

Example

system = powerSystem("case14.h5")
 device = measurement()
@@ -246,7 +246,7 @@
 power!(system, analysis)
 
 addWattmeter!(system, device, analysis)
-statusWattmeter!(system, device; outserviceBus = 14, inserviceFrom = 10, outserviceTo = 2)
source
JuliaGrid.@wattmeterMacro
@wattmeter(label, varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo,
+statusWattmeter!(system, device; outserviceBus = 14, inserviceFrom = 10, outserviceTo = 2)
source
JuliaGrid.@wattmeterMacro
@wattmeter(label, varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo,
     noise)

The macro generates a template for a wattmeter, which can be utilized to define a wattmeter using the addWattmeter! function.

Keywords

To establish the wattmeter template, users can set default variance and status values for wattmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.

Units

The default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.

Examples

Adding wattmeters using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -266,7 +266,7 @@
 
 @wattmeter(label = "Wattmeter ?", varianceBus = 1e-1, varianceFrom = 1e-2)
 addWattmeter!(system, device; bus = "Bus 2", active = 40.0)
-addWattmeter!(system, device; from = "Branch 1", active = 10.0)
source

Varmeter

JuliaGrid.addVarmeter!Method
addVarmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, reactive,
+addWattmeter!(system, device; from = "Branch 1", active = 10.0)
source

Varmeter

JuliaGrid.addVarmeter!Method
addVarmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, reactive,
     variance, noise, status)

The function adds a new varmeter that measures reactive power injection or reactive power flow to the Measurement type within a given PowerSystem type. The varmeter can be added to an already defined bus or branch.

Keywords

The varmeter is defined with the following keywords:

  • label: Unique label for the varmeter.
  • bus: Label of the bus if the varmeter is located at the bus.
  • from: Label of the branch if the varmeter is located at the from-bus end.
  • to: Label of the branch if the varmeter is located at the to-bus end.
  • reactive (pu or VAr): Reactive power value.
  • variance (pu or VAr): Variance of the reactive power measurement.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the reactive,
    • noise = false: uses the reactive value only.
  • status: Operating status of the varmeter:
    • status = 1: in-service,
    • status = 0: out-of-service.

Updates

The function updates the varmeter field of the Measurement composite type.

Default Settings

Default settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to varmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for varmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @varmeter macro.

Units

The default units for the reactive and variance keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.

Examples

Adding varmeters using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -284,7 +284,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addVarmeter!(system, device; label = "Varmeter 1", bus = "Bus 2", reactive = 40.0)
-addVarmeter!(system, device; label = "Varmeter 2", from = "Branch 1", reactive = 10.0)
source
JuliaGrid.addVarmeter!Method
addVarmeter!(system::PowerSystem, device::Measurement, analysis::AC;
+addVarmeter!(system, device; label = "Varmeter 2", from = "Branch 1", reactive = 10.0)
source
JuliaGrid.addVarmeter!Method
addVarmeter!(system::PowerSystem, device::Measurement, analysis::AC;
     varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)

The function incorporates varmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact reactive power injections at buses and reactive power flows in branches defined in the AC type.

Keywords

  • varianceBus (pu or VAr): Measurement variance for varmeters at the buses.
  • statusBus: Operating status of the varmeters at the buses:
    • statusBus = 1: in-service,
    • statusBus = 0: out-of-service.
  • varianceFrom (pu or VAr): Measurement variance for varmeters at the from-bus ends.
  • statusFrom: Operating status of the varmeters at the from-bus ends:
    • statusFrom = 1: in-service,
    • statusFrom = 0: out-of-service.
  • varianceTo (pu or VAr): Measurement variance for varmeters at the to-bus ends.
  • statusTo: Operating status of the varmeters at the to-bus ends:
    • statusTo = 1: in-service,
    • statusTo = 0: out-of-service.
  • noise: Specifies how to generate the measurement mean:
    • noise = true: adds white Gaussian noise with the variance to the reactive powers,
    • noise = false: uses the exact reactive power values.

Updates

The function updates the varmeter field of the Measurement composite type.

Default Settings

Default settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @varmeter macro.

Units

The default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.

Example

system = powerSystem("case14.h5")
 device = measurement()
 
@@ -300,7 +300,7 @@
 power!(system, analysis)
 
 @varmeter(label = "Varmeter ?")
-addVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)
source
JuliaGrid.updateVarmeter!Function
updateVarmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
+addVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)
source
JuliaGrid.updateVarmeter!Function
updateVarmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];
     kwargs...)

The function allows for the alteration of parameters for a varmeter.

Arguments

If the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific varmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVarmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing varmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the varmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addVarmeter! function.

Example

system = powerSystem()
 device = measurement()
 
@@ -309,7 +309,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addVarmeter!(system, device; label = "Varmeter 1", from = "Branch 1", reactive = 1.1)
-updateVarmeter!(system, device; label = "Varmeter 1", reactive = 1.2, variance = 1e-4)
source
JuliaGrid.statusVarmeter!Function
statusVarmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
+updateVarmeter!(system, device; label = "Varmeter 1", reactive = 1.2, variance = 1e-4)
source
JuliaGrid.statusVarmeter!Function
statusVarmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
     inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,
     redundancy, redundancyBus, redundancyFrom, redundancyTo)

The function generates a set of varmeters, assigning varmeters randomly to either in-service or out-of-service states based on specified keywords.

Keywords

Users may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:

  • inservice: Sets the number of in-service varmeters or allows fine-tuning:
    • inserviceBus: sets only varmeters loacted at the bus,
    • inserviceFrom: sets only varmeters loacted at the from-bus end,
    • inserviceTo: sets only varmeters loacted at the to-bus end.
  • outservice: Sets the number of out-of-service varmeters or allows fine-tuning:
    • outserviceBus: sets only varmeters loacted at the bus,
    • outserviceFrom: sets only varmeters loacted at the from-bus end,
    • outserviceTo: sets only varmeters loacted at the to-bus end.
  • redundancy: Determines in-service varmeters based on redundancy or allows fine-tuning:
    • redundancyBus: determines only varmeters loacted at the bus,
    • redundancyFrom: determines only varmeters loacted at the from-bus end,
    • redundancyTo: determines only varmeters loacted at the to-bus end.

Updates

The function updates the status field within the Varmeter type.

Example

system = powerSystem("case14.h5")
 device = measurement()
@@ -326,7 +326,7 @@
 power!(system, analysis)
 
 addVarmeter!(system, device, analysis)
-statusVarmeter!(system, device; inserviceFrom = 20)
source
JuliaGrid.@varmeterMacro
@varmeter(label, varinaceBus, varianceFrom, varianceTo, statusBus, statusFrom, statusTo,
+statusVarmeter!(system, device; inserviceFrom = 20)
source
JuliaGrid.@varmeterMacro
@varmeter(label, varinaceBus, varianceFrom, varianceTo, statusBus, statusFrom, statusTo,
     noise)

The macro generates a template for a varmeter, which can be utilized to define a varmeter using the addVarmeter! function.

Keywords

To establish the varmeter template, users can set default variance and status values for varmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.

Units

The default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to usevolt-amperes reactive (VAr) as the units by applying the @power macro.

Examples

Adding varmeters using the default unit system:

system = powerSystem()
 device = measurement()
 
@@ -346,7 +346,7 @@
 
 @varmeter(label = "Varmeter ?", varianceBus = 1e-1, varianceFrom = 1e-2)
 addVarmeter!(system, device; bus = "Bus 2", reactive = 40.0)
-addVarmeter!(system, device; from = "Branch 1", reactive = 10.0)
source

PMU

JuliaGrid.addPmu!Method
addPmu!(system::PowerSystem, device::Measurement; label, bus, from, to, magnitude,
+addVarmeter!(system, device; from = "Branch 1", reactive = 10.0)
source

PMU

JuliaGrid.addPmu!Method
addPmu!(system::PowerSystem, device::Measurement; label, bus, from, to, magnitude,
     varianceMagnitude, statusMagnitude, angle, varianceAngle, statusAngle,
     noise, correlated, polar)

The function adds a new PMU to the Measurement type within a given PowerSystem type. The PMU can be added to an already defined bus or branch. When defining the PMU, it is essential to provide the bus voltage magnitude and angle if the PMU is located at a bus or the branch current magnitude and angle if the PMU is located at a branch.

Keywords

The PMU is defined with the following keywords:

  • label: Unique label for the PMU.
  • bus: Label of the bus if the PMU is located at the bus.
  • from: Label of the branch if the PMU is located at the from-bus end.
  • to: Label of the branch if the PMU is located at the to-bus end.
  • magnitude (pu or V, A): Bus voltage or branch current magnitude value.
  • varianceMagnitude (pu or V, A): Magnitude measurement variance.
  • statusMagnitude: Operating status of the magnitude measurement:
    • statusMagnitude = 1: in-service,
    • statusMagnitude = 0: out-of-service.
  • angle (rad or deg): Bus voltage or branch current angle value.
  • varianceAngle (rad or deg): Angle measurement variance.
  • statusAngle: Operating status of the angle measurement:
    • statusAngle = 1: in-service,
    • statusAngle = 0: out-of-service.
  • noise: Specifies how to generate the measurement means:
    • noise = true: adds white Gaussian noises with variances to the magnitude and angle,
    • noise = false: uses the magnitude and angle values only.
  • correlated: Specifies error correlation for PMUs for algorithms utilizing rectangular coordinates:
    • correlated = true: considers correlated errors,
    • correlated = false: disregards correlations between errors.
  • polar: Chooses the coordinate system for including phasor measurements in AC state estimation:
    • polar = true: adopts the polar coordinate system,
    • polar = false: adopts the rectangular coordinate system.

Updates

The function updates the pmu field of the Measurement composite type.

Default Settings

Default settings for certain keywords are as follows: varianceMagnitude = 1e-5, statusMagnitude = 1, varianceAngle = 1e-5, statusAngle = 1, noise = false, correlated = false, and polar = false, which apply to PMUs located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for PMUs positioned at the buses, from-bus ends, or to-bus ends of branches using the @pmu macro.

Units

The default units for the magnitude, varianceMagnitude, and angle, varianceAngle keywords are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) when the PMU is located at a bus using the @voltage macro, or amperes (A) and degrees (deg) when the PMU is located at a branch through the use of the @current macro.

Examples

Adding PMUs using the default unit system:

system = powerSystem()
 device = measurement()
@@ -366,7 +366,7 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)
 
 addPmu!(system, device; label = "PMU 1", bus = "Bus 1", magnitude = 145, angle = -5.7)
-addPmu!(system, device; label = "PMU 2", from = "Branch 1", magnitude = 481, angle = 5.7)
source
JuliaGrid.addPmu!Method
addPmu!(system::PowerSystem, device::Measurement, analysis::AC;
+addPmu!(system, device; label = "PMU 2", from = "Branch 1", magnitude = 481, angle = 5.7)
source
JuliaGrid.addPmu!Method
addPmu!(system::PowerSystem, device::Measurement, analysis::AC;
     varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,
     varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,
     varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo,
@@ -385,14 +385,14 @@
 current!(system, analysis)
 
 @pmu(label = "PMU ?")
-addPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)
source
JuliaGrid.updatePmu!Function
updatePmu!(system::PowerSystem, device::Measurement, [analysis::Analysis];
+addPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)
source
JuliaGrid.updatePmu!Function
updatePmu!(system::PowerSystem, device::Measurement, [analysis::Analysis];
     kwargs...)

The function allows for the alteration of parameters for a PMU.

Arguments

If the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific PMU, provide the necessary kwargs input arguments in accordance with the keywords specified in the addPmu! function, along with their respective values. Ensure that the label keyword matches the label of the existing PMU you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the pmu field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addPmu! function.

Example

system = powerSystem()
 device = measurement()
 
 addBus!(system; label = "Bus 1", base = 132e3)
 
 addPmu!(system, device; label = "PMU 1", bus = "Bus 1", magnitude = 1.1, angle = -0.1)
-updatePmu!(system, device; label = "PMU 1", magnitude = 1.05)
source
JuliaGrid.statusPmu!Function
statusPmu!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
+updatePmu!(system, device; label = "PMU 1", magnitude = 1.05)
source
JuliaGrid.statusPmu!Function
statusPmu!(system::PowerSystem, device::Measurement; inservice, inserviceBus,
     inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,
     redundancy, redundancyBus, redundancyFrom, redundancyTo)

The function generates a set of PMUs, assigning PMUs randomly to either in-service or out-of-service states based on specified keywords. It is important to note that when we refer to PMU, we encompass both magnitude and angle measurements.

Keywords

Users may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:

  • inservice: Sets the number of in-service PMUs or allows fine-tuning:
    • inserviceBus: sets only PMUs loacted at the bus,
    • inserviceFrom: sets only PMUs loacted at the from-bus end,
    • inserviceTo: sets only PMUs loacted at the to-bus end.
  • outservice: Sets the number of out-of-service PMUs or allows fine-tuning:
    • outserviceBus: sets only PMUs loacted at the bus,
    • outserviceFrom: sets only PMUs loacted at the from-bus end,
    • outserviceTo: sets only PMUs loacted at the to-bus end.
  • redundancy: Determines in-service PMUs based on redundancy or allows fine-tuning:
    • redundancyBus: determines only PMUs loacted at the bus,
    • redundancyFrom: determines only PMUs loacted at the from-bus end,
    • redundancyTo: determines only PMUs loacted at the to-bus end.

Updates

The function updates the status fields within the PMU type.

Example

system = powerSystem("case14.h5")
 device = measurement()
@@ -409,7 +409,7 @@
 current!(system, analysis)
 
 addPmu!(system, device, analysis)
-statusPmu!(system, device; inserviceBus = 14)
source
JuliaGrid.@pmuMacro
@pmu(label, varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,
+statusPmu!(system, device; inserviceBus = 14)
source
JuliaGrid.@pmuMacro
@pmu(label, varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,
     varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,
     varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo, noise,
     correlated, polar)

The macro generates a template for a PMU, which can be utilized to define a PMU using the addPmu! function.

Keywords

To establish the PMU template, users have the option to set default values for magnitude and angle variances, as well as statuses for each component of the phasor. This can be done for PMUs located at the buses using the varianceMagnitudeBus, varianceAngleBus, statusMagnitudeBus, and statusAngleBus keywords.

The same configuration can be applied at both the from-bus ends of the branches using the varianceMagnitudeFrom, varianceAngleFrom, statusMagnitudeFrom, and statusAngleFrom keywords.

For PMUs located at the to-bus ends of the branches, users can use the varianceMagnitudeTo, varianceAngleTo, statusMagnitudeTo, and statusAngleTo keywords.

Additionally, users can configure the pattern for labels using the label keyword, specify the type of noise, and indicate the correlated and polar system utilized for managing phasors during state estimation.

Units

By default, the units for variances are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) as the units for PMUs located at the buses by using the @voltage macro, or they can switch to amperes (A) and degrees (deg) as the units for PMUs located at the branches by using the @current macro.

Examples

Adding PMUs using the default unit system:

system = powerSystem()
@@ -432,4 +432,4 @@
 
 @pmu(label = "PMU ?", varianceAngleBus = 5.73e-5, varianceMagnitudeFrom = 0.0481)
 addPmu!(system, device; bus = "Bus 1", magnitude = 145.2, angle = -5.73)
-addPmu!(system, device; from = "Branch 1", magnitude = 481.125, angle = -11.46)
source
+addPmu!(system, device; from = "Branch 1", magnitude = 481.125, angle = -11.46)
source
diff --git a/dev/api/optimalPowerFlow/index.html b/dev/api/optimalPowerFlow/index.html index 46d76f1a..518e5a63 100644 --- a/dev/api/optimalPowerFlow/index.html +++ b/dev/api/optimalPowerFlow/index.html @@ -3,11 +3,11 @@ magnitude, angle, active, reactive)

The function sets up the optimization model for solving the AC optimal power flow problem.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the AC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type.

Keywords

JuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:

Additionally, users can modify variable names used for printing and writing through the keywords magnitude, angle, active, and reactive. For instance, users can choose magnitude = "V" and angle = "θ" to display equations in a more readable format.

Returns

The function returns an instance of the ACOptimalPowerFlow type, which includes the following fields:

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
-analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function solves the AC optimal power flow model, computing the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.

Updates

The calculated active and reactive powers, as well as voltage magnitudes and angles, are stored in the power.generator and voltage fields of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function solves the AC optimal power flow model, computing the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.

Updates

The calculated active and reactive powers, as well as voltage magnitudes and angles, are stored in the power.generator and voltage fields of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
-solve!(system, analysis)
source
JuliaGrid.startingPrimal!Method
startingPrimal!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function retrieves the active and reactive power outputs of the generators, as well as the voltage magnitudes and angles from the PowerSystem composite type. It then assigns these values to the ACOptimalPowerFlow type, allowing users to initialize starting primal values as needed.

Updates

This function only updates the voltage and generator fields of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+solve!(system, analysis)
source
JuliaGrid.startingPrimal!Method
startingPrimal!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function retrieves the active and reactive power outputs of the generators, as well as the voltage magnitudes and angles from the PowerSystem composite type. It then assigns these values to the ACOptimalPowerFlow type, allowing users to initialize starting primal values as needed.

Updates

This function only updates the voltage and generator fields of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
@@ -16,7 +16,7 @@
 updateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)
 
 startingPrimal!(system, analysis)
-solve!(system, analysis)
source
JuliaGrid.startingDual!Method
startingDual!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function removes all values of the dual variables.

Updates

This function only updates the dual field of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+solve!(system, analysis)
source
JuliaGrid.startingDual!Method
startingDual!(system::PowerSystem, analysis::ACOptimalPowerFlow)

The function removes all values of the dual variables.

Updates

This function only updates the dual field of the ACOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)
@@ -25,14 +25,14 @@
 updateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)
 
 startingDual!(system, analysis)
-solve!(system, analysis)
source

DC Optimal Power Flow

JuliaGrid.dcOptimalPowerFlowFunction
dcOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name, angle, active)

The function sets up the optimization model for solving the DC optimal power flow problem.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the DC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.

Updates

If the DC model has not been created, the function automatically initiates an update within the dc field of the PowerSystem type.

Keywords

JuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:

  • bridge: manage the bridging mechanism (default: false),
  • name: manage the creation of string names (default: true).

Additionally, users can modify variable names used for printing and writing through the keywords angle and active. For instance, users can choose angle = "θ" to display equations in a more readable format.

Returns

The function returns an instance of the DCOptimalPowerFlow type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angle,
  • power: The variable allocated to store the active powers,
  • method: The JuMP model, references to the variables, constraints, and objective.

Example

system = powerSystem("case14.h5")
+solve!(system, analysis)
source

DC Optimal Power Flow

JuliaGrid.dcOptimalPowerFlowFunction
dcOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name, angle, active)

The function sets up the optimization model for solving the DC optimal power flow problem.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the DC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.

Updates

If the DC model has not been created, the function automatically initiates an update within the dc field of the PowerSystem type.

Keywords

JuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:

  • bridge: manage the bridging mechanism (default: false),
  • name: manage the creation of string names (default: true).

Additionally, users can modify variable names used for printing and writing through the keywords angle and active. For instance, users can choose angle = "θ" to display equations in a more readable format.

Returns

The function returns an instance of the DCOptimalPowerFlow type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angle,
  • power: The variable allocated to store the active powers,
  • method: The JuMP model, references to the variables, constraints, and objective.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
-analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function solves the DC optimal power flow model, computing the active power outputs of the generators, as well as the bus voltage angles.

Updates

The calculated active powers, as well as voltage angles, are stored in the power.generator and voltage fields of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function solves the DC optimal power flow model, computing the active power outputs of the generators, as well as the bus voltage angles.

Updates

The calculated active powers, as well as voltage angles, are stored in the power.generator and voltage fields of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)
-solve!(system, analysis)
source
JuliaGrid.startingPrimal!Method
startingPrimal!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function retrieves the active power outputs of the generators and the bus voltage angles from the PowerSystem composite type. These values are then assigned to the DCOptimalPowerFlow type, enabling users to initialize starting primal values according to their requirements.

Updates

This function only updates the voltage and generator fields of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+solve!(system, analysis)
source
JuliaGrid.startingPrimal!Method
startingPrimal!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function retrieves the active power outputs of the generators and the bus voltage angles from the PowerSystem composite type. These values are then assigned to the DCOptimalPowerFlow type, enabling users to initialize starting primal values according to their requirements.

Updates

This function only updates the voltage and generator fields of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)
@@ -41,7 +41,7 @@
 updateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)
 
 startingPrimal!(system, analysis)
-solve!(system, analysis)
source
JuliaGrid.startingDual!Method
startingDual!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function removes all values of the dual variables.

Updates

This function only updates the dual field of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
+solve!(system, analysis)
source
JuliaGrid.startingDual!Method
startingDual!(system::PowerSystem, analysis::DCOptimalPowerFlow)

The function removes all values of the dual variables.

Updates

This function only updates the dual field of the DCOptimalPowerFlow type.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)
@@ -50,4 +50,4 @@
 updateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)
 
 startingDual!(system, analysis)
-solve!(system, analysis)
source
+solve!(system, analysis)source diff --git a/dev/api/powerFlow/index.html b/dev/api/powerFlow/index.html index b45412ea..839d0962 100644 --- a/dev/api/powerFlow/index.html +++ b/dev/api/powerFlow/index.html @@ -5,26 +5,26 @@ analysis = newtonRaphson(system)

Set up the Newton-Raphson method utilizing QR factorization:

system = powerSystem("case14.h5")
 acModel!(system)
 
-analysis = newtonRaphson(system, QR)
source
JuliaGrid.fastNewtonRaphsonBXFunction
fastNewtonRaphsonBX(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the fast Newton-Raphson method of version BX to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • QR: utilizes QR factorization.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The Jacobian matrices, their factorizations, mismatches, increments, and indices.

Examples

Set up the fast Newton-Raphson method utilizing LU factorization:

system = powerSystem("case14.h5")
+analysis = newtonRaphson(system, QR)
source
JuliaGrid.fastNewtonRaphsonBXFunction
fastNewtonRaphsonBX(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the fast Newton-Raphson method of version BX to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • QR: utilizes QR factorization.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The Jacobian matrices, their factorizations, mismatches, increments, and indices.

Examples

Set up the fast Newton-Raphson method utilizing LU factorization:

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = fastNewtonRaphsonBX(system)

Set up the fast Newton-Raphson method utilizing QR factorization:

system = powerSystem("case14.h5")
 acModel!(system)
 
-analysis = fastNewtonRaphsonBX(system, QR)
source
JuliaGrid.fastNewtonRaphsonXBFunction
fastNewtonRaphsonXB(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the fast Newton-Raphson method of version XB to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • QR: utilizes QR factorization.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The Jacobian matrices, their factorizations, mismatches, increments, and indices.

Examples

Set up the fast Newton-Raphson method utilizing LU factorization:

system = powerSystem("case14.h5")
+analysis = fastNewtonRaphsonBX(system, QR)
source
JuliaGrid.fastNewtonRaphsonXBFunction
fastNewtonRaphsonXB(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the fast Newton-Raphson method of version XB to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • QR: utilizes QR factorization.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The Jacobian matrices, their factorizations, mismatches, increments, and indices.

Examples

Set up the fast Newton-Raphson method utilizing LU factorization:

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = fastNewtonRaphsonXB(system)

Set up the fast Newton-Raphson method utilizing QR factorization:

system = powerSystem("case14.h5")
 acModel!(system)
 
-analysis = fastNewtonRaphsonXB(system, QR)
source
JuliaGrid.gaussSeidelFunction
gaussSeidel(system::PowerSystem)

The function sets up the Gauss-Seidel method to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The bus complex voltages and indices.

Example

system = powerSystem("case14.h5")
+analysis = fastNewtonRaphsonXB(system, QR)
source
JuliaGrid.gaussSeidelFunction
gaussSeidel(system::PowerSystem)

The function sets up the Gauss-Seidel method to solve the AC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework.

Updates

If the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.

Returns

The function returns an instance of the ACPowerFlow type, which includes the following fields:

  • voltage: The bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • current: The variable allocated to store the currents.
  • method: The bus complex voltages and indices.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
-analysis = gaussSeidel(system)
source
JuliaGrid.mismatch!Method
mismatch!(system::PowerSystem, analysis::ACPowerFlow)

The function calculates both active and reactive power injection mismatches.

Updates

This function updates the mismatch variables in the Newton-Raphson and fast Newton-Raphson methods. It should be employed during the iteration loop before invoking the solve! function.

Returns

The function returns maximum absolute values of the active and reactive power injection mismatches, which can be utilized to terminate the iteration loop of the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel methods employed to solve the AC power flow problem.

Example

system = powerSystem("case14.h5")
+analysis = gaussSeidel(system)
source
JuliaGrid.mismatch!Method
mismatch!(system::PowerSystem, analysis::ACPowerFlow)

The function calculates both active and reactive power injection mismatches.

Updates

This function updates the mismatch variables in the Newton-Raphson and fast Newton-Raphson methods. It should be employed during the iteration loop before invoking the solve! function.

Returns

The function returns maximum absolute values of the active and reactive power injection mismatches, which can be utilized to terminate the iteration loop of the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel methods employed to solve the AC power flow problem.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
-mismatch!(system, analysis)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACPowerFlow)

The function employs the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel method to solve the AC power flow model and calculate bus voltage magnitudes and angles.

After the mismatch! function is called, this function should be executed to perform a single iteration of the method.

Updates

The calculated voltages are stored in the voltage field of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
+mismatch!(system, analysis)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACPowerFlow)

The function employs the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel method to solve the AC power flow model and calculate bus voltage magnitudes and angles.

After the mismatch! function is called, this function should be executed to perform a single iteration of the method.

Updates

The calculated voltages are stored in the voltage field of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -34,7 +34,7 @@
         break
     end
     solve!(system, analysis)
-end
source
JuliaGrid.startingVoltage!Function
startingVoltage!(system::PowerSystem, analysis::ACPowerFlow)

The function extracts bus voltage magnitudes and angles from the PowerSystem composite type and assigns them to the ACPowerFlow type, enabling users to initialize voltage values as required.

Updates

This function only updates the voltage field of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
+end
source
JuliaGrid.startingVoltage!Function
startingVoltage!(system::PowerSystem, analysis::ACPowerFlow)

The function extracts bus voltage magnitudes and angles from the PowerSystem composite type and assigns them to the ACPowerFlow type, enabling users to initialize voltage values as required.

Updates

This function only updates the voltage field of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -55,7 +55,7 @@
         break
     end
     solve!(system, analysis)
-end
source
JuliaGrid.reactiveLimit!Function
reactiveLimit!(system::PowerSystem, analysis::ACPowerFlow)

The function verifies whether the generators in a power system exceed their reactive power limits. This is done by setting the reactive power of the generators to within the limits if they are violated after determining the bus voltage magnitudes and angles. If the limits are violated, the corresponding generator buses or the slack bus are converted to demand buses.

Updates

The function assigns values to the generator.output.active and bus.supply.active variables of the PowerSystem type.

Additionally, it examines the reactive powers of the generators and adjusts them to their maximum or minimum values if they exceed the specified threshold. This results in the modification of the variable generator.output.reactive of the PowerSystem type accordingly.

As a result of this adjustment, the bus.supply.reactive variable is also updated, and the bus types specified in bus.layout.type are modified. If the slack bus is converted, the bus.layout.slack field is correspondingly adjusted.

Returns

The function returns the variable to indicate which buses violate the limits, with -1 indicating a violation of the minimum limits and 1 indicating a violation of the maximum limits.

Example

system = powerSystem("case14.h5")
+end
source
JuliaGrid.reactiveLimit!Function
reactiveLimit!(system::PowerSystem, analysis::ACPowerFlow)

The function verifies whether the generators in a power system exceed their reactive power limits. This is done by setting the reactive power of the generators to within the limits if they are violated after determining the bus voltage magnitudes and angles. If the limits are violated, the corresponding generator buses or the slack bus are converted to demand buses.

Updates

The function assigns values to the generator.output.active and bus.supply.active variables of the PowerSystem type.

Additionally, it examines the reactive powers of the generators and adjusts them to their maximum or minimum values if they exceed the specified threshold. This results in the modification of the variable generator.output.reactive of the PowerSystem type accordingly.

As a result of this adjustment, the bus.supply.reactive variable is also updated, and the bus types specified in bus.layout.type are modified. If the slack bus is converted, the bus.layout.slack field is correspondingly adjusted.

Returns

The function returns the variable to indicate which buses violate the limits, with -1 indicating a violation of the minimum limits and 1 indicating a violation of the maximum limits.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -76,7 +76,7 @@
         break
     end
     solve!(system, analysis)
-end
source
JuliaGrid.adjustAngle!Function
adjustAngle!(system::PowerSystem, analysis::ACPowerFlow; slack)

The function modifies the bus voltage angles based on a different slack bus than the one identified by the bus.layout.slack field.

For instance, if the reactive power of the generator exceeds the limit on the slack bus, the reactiveLimit! function will change that bus to the demand bus and designate the first generator bus in the sequence as the new slack bus. After obtaining the updated AC power flow solution based on the new slack bus, it is possible to adjust the voltage angles to align with the angle of the original slack bus.

Keyword

The slack keyword specifies the bus label for which we want to adjust voltage angles.

Updates

This function only updates the voltage.angle variable of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
+end
source
JuliaGrid.adjustAngle!Function
adjustAngle!(system::PowerSystem, analysis::ACPowerFlow; slack)

The function modifies the bus voltage angles based on a different slack bus than the one identified by the bus.layout.slack field.

For instance, if the reactive power of the generator exceeds the limit on the slack bus, the reactiveLimit! function will change that bus to the demand bus and designate the first generator bus in the sequence as the new slack bus. After obtaining the updated AC power flow solution based on the new slack bus, it is possible to adjust the voltage angles to align with the angle of the original slack bus.

Keyword

The slack keyword specifies the bus label for which we want to adjust voltage angles.

Updates

This function only updates the voltage.angle variable of the ACPowerFlow type.

Example

system = powerSystem("case14.h5")
 acModel!(system)
 
 analysis = newtonRaphson(system)
@@ -99,14 +99,14 @@
     solve!(system, analysis)
 end
 
-adjustAngle!(system, analysis; slack = 1)
source

DC Power Flow

JuliaGrid.dcPowerFlowFunction
dcPowerFlow(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the framework to solve the DC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • LDLt: utilizes LDLt factorization,
  • QR: utilizes QR factorization.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCPowerFlow type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The factorized nodal matrix.

Examples

Set up the DC power flow utilizing LU factorization:

system = powerSystem("case14.h5")
+adjustAngle!(system, analysis; slack = 1)
source

DC Power Flow

JuliaGrid.dcPowerFlowFunction
dcPowerFlow(system::PowerSystem, [factorization::Factorization = LU])

The function sets up the framework to solve the DC power flow.

Arguments

The function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations. It can take one of the following values:

  • LU: utilizes LU factorization (default),
  • LDLt: utilizes LDLt factorization,
  • QR: utilizes QR factorization.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCPowerFlow type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The factorized nodal matrix.

Examples

Set up the DC power flow utilizing LU factorization:

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)

Set up the DC power flow utilizing QR factorization:

system = powerSystem("case14.h5")
 dcModel!(system)
 
-analysis = dcPowerFlow(system, QR)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCPowerFlow)

The function solves the DC power flow model and calculates bus voltage angles.

Updates

The calculated voltage angles are stored in the voltage field of the DCPowerFlow type.

Example

system = powerSystem("case14.h5")
+analysis = dcPowerFlow(system, QR)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCPowerFlow)

The function solves the DC power flow model and calculates bus voltage angles.

Updates

The calculated voltage angles are stored in the voltage field of the DCPowerFlow type.

Example

system = powerSystem("case14.h5")
 dcModel!(system)
 
 analysis = dcPowerFlow(system)
-solve!(system, analysis)
source
+solve!(system, analysis)source diff --git a/dev/api/powerSystemModel/index.html b/dev/api/powerSystemModel/index.html index 6d4f56a0..bda59063 100644 --- a/dev/api/powerSystemModel/index.html +++ b/dev/api/powerSystemModel/index.html @@ -1,18 +1,18 @@ -Power System Model · JuliaGrid

Power System Model

For further information on this topic, please see the Power System Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate power system structures, as well as to build AC and DC models of power systems.

To load power system model API functionalities into the current scope, utilize the following command:

using JuliaGrid

Power System
Bus
Branch
Generator

Power System

JuliaGrid.powerSystemFunction
powerSystem(file::String)

The function builds the composite type PowerSystem and populates bus, branch, generator and base fields. Once the composite type PowerSystem has been created, it is possible to add new buses, branches, or generators, or modify the parameters of existing ones.

Argument

It requires a string path to:

  • the HDF5 file with the .h5 extension,
  • the Matpower file with the .m extension.

Returns

The PowerSystem composite type with the following fields:

  • bus: Data related to buses.
  • branch: Data related to branches.
  • generator: Data related to generators.
  • base: Base power and base voltages.
  • model: Data associated with AC and DC analyses.

Units

JuliaGrid stores all data in per-units and radians format which are fixed, the exceptions are base values in volt-amperes and volts. The prefixes for these base values can be changed using the @base macro.

Example

system = powerSystem("case14.h5")
source
powerSystem()

Alternatively, the PowerSystem composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed. This generates an empty PowerSystem type, with only the base power initialized to 1.0e8 volt-amperes (VA).

Example

system = powerSystem()
source
JuliaGrid.savePowerSystemFunction
savePowerSystem(system::PowerSystem; path::String, reference::String, note::String)

The function saves the power system's data in the HDF5 file using the fields bus, branch, generator, and base from the PowerSystem composite type.

Keywords

The location and file name of the HDF5 file is specified by the mandatory keyword path in the format of "path/name.h5". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.

View HDF5 File

To view the saved HDF5 file, you can use the HDFView software.

Example

system = powerSystem("case14.m")
-savePowerSystem(system; path = "D:/case14.h5")
source
JuliaGrid.acModel!Function
acModel!(system::PowerSystem)

The function generates vectors and matrices based on the power system topology and parameters associated with AC analyses.

Updates

The function updates the model.ac field within the PowerSystem composite type, populating the following variables:

  • nodalMatrix: The nodal matrix.
  • nodalMatrixTranspose: The transpose of the nodal matrix.
  • nodalFromFrom: The Y-parameters of the two-port branches.
  • nodalFromTo: The Y-parameters of the two-port branches.
  • nodalToTo: The Y-parameters of the two-port branches.
  • nodalToFrom: The Y-parameters of the two-port branches.
  • admittance: The branch admittances.

Example

system = powerSystem("case14.h5")
-acModel!(system)
source
JuliaGrid.dcModel!Function
dcModel!(system::PowerSystem)

The function generates vectors and matrices based on the power system topology and parameters associated with DC analyses.

Updates

The function updates the model.dc field within the PowerSystem composite type, populating the following variables:

  • nodalMatrix: The nodal matrix.
  • admittance: The branch admittances.
  • shiftPower: The active powers related to phase-shifting transformers.

Example

system = powerSystem("case14.h5")
-dcModel!(system)
source

Bus

JuliaGrid.addBus!Function
addBus!(system::PowerSystem; label, type, active, reactive, conductance, susceptance,
+Power System Model · JuliaGrid

Power System Model

For further information on this topic, please see the Power System Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate power system structures, as well as to build AC and DC models of power systems.

To load power system model API functionalities into the current scope, utilize the following command:

using JuliaGrid

Power System
Bus
Branch
Generator

Power System

JuliaGrid.powerSystemFunction
powerSystem(file::String)

The function builds the composite type PowerSystem and populates bus, branch, generator and base fields. Once the composite type PowerSystem has been created, it is possible to add new buses, branches, or generators, or modify the parameters of existing ones.

Argument

It requires a string path to:

  • the HDF5 file with the .h5 extension,
  • the Matpower file with the .m extension.

Returns

The PowerSystem composite type with the following fields:

  • bus: Data related to buses.
  • branch: Data related to branches.
  • generator: Data related to generators.
  • base: Base power and base voltages.
  • model: Data associated with AC and DC analyses.

Units

JuliaGrid stores all data in per-units and radians format which are fixed, the exceptions are base values in volt-amperes and volts. The prefixes for these base values can be changed using the @base macro.

Example

system = powerSystem("case14.h5")
source
powerSystem()

Alternatively, the PowerSystem composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed. This generates an empty PowerSystem type, with only the base power initialized to 1.0e8 volt-amperes (VA).

Example

system = powerSystem()
source
JuliaGrid.savePowerSystemFunction
savePowerSystem(system::PowerSystem; path::String, reference::String, note::String)

The function saves the power system's data in the HDF5 file using the fields bus, branch, generator, and base from the PowerSystem composite type.

Keywords

The location and file name of the HDF5 file is specified by the mandatory keyword path in the format of "path/name.h5". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.

View HDF5 File

To view the saved HDF5 file, you can use the HDFView software.

Example

system = powerSystem("case14.m")
+savePowerSystem(system; path = "D:/case14.h5")
source
JuliaGrid.acModel!Function
acModel!(system::PowerSystem)

The function generates vectors and matrices based on the power system topology and parameters associated with AC analyses.

Updates

The function updates the model.ac field within the PowerSystem composite type, populating the following variables:

  • nodalMatrix: The nodal matrix.
  • nodalMatrixTranspose: The transpose of the nodal matrix.
  • nodalFromFrom: The Y-parameters of the two-port branches.
  • nodalFromTo: The Y-parameters of the two-port branches.
  • nodalToTo: The Y-parameters of the two-port branches.
  • nodalToFrom: The Y-parameters of the two-port branches.
  • admittance: The branch admittances.

Example

system = powerSystem("case14.h5")
+acModel!(system)
source
JuliaGrid.dcModel!Function
dcModel!(system::PowerSystem)

The function generates vectors and matrices based on the power system topology and parameters associated with DC analyses.

Updates

The function updates the model.dc field within the PowerSystem composite type, populating the following variables:

  • nodalMatrix: The nodal matrix.
  • admittance: The branch admittances.
  • shiftPower: The active powers related to phase-shifting transformers.

Example

system = powerSystem("case14.h5")
+dcModel!(system)
source

Bus

JuliaGrid.addBus!Function
addBus!(system::PowerSystem; label, type, active, reactive, conductance, susceptance,
     magnitude, angle, minMagnitude, maxMagnitude, base, area, lossZone)

The function adds a new bus to the PowerSystem composite type.

Keywords

The bus is defined with the following keywords:

  • label: Unique label for the bus.
  • type: Bus type:
    • type = 1: demand bus (PQ),
    • type = 2: generator bus (PV),
    • type = 3: slack bus (Vθ).
  • active (pu or W): Active power demand at the bus.
  • reactive (pu or VAr): Reactive power demand at the bus.
  • conductance (pu or W): Active power demanded of the shunt element.
  • susceptance (pu or VAr): Reactive power injected/demanded of the shunt element.
  • magnitude (pu or V): Initial value of the bus voltage magnitude.
  • angle (rad or deg): Initial value of the bus voltage angle.
  • minMagnitude (pu or V): Minimum bus voltage magnitude value.
  • maxMagnitude (pu or V): Maximum bus voltage magnitude value.
  • base (V): Voltage base value.
  • area: Area number.
  • lossZone: Loss zone.

Updates

The function updates the bus field of the PowerSystem composite type.

Default Settings

The default settings for certain keywords are as follows: type = 1, magnitude = 1.0, minMagnitude = 0.9, maxMagnitude = 1.1, and base = 138e3. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @bus macro.

Units

By default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.

Examples

Adding a bus using the default unit system:

system = powerSystem()
 
 addBus!(system; label = "Bus 1", active = 0.25, angle = 0.175, base = 132e3)

Adding a bus using a custom unit system:

@power(MW, MVAr, MVA)
 @voltage(pu, deg, kV)
 system = powerSystem()
 
-addBus!(system; label = "Bus 1", active = 25.0, angle = 10.026, base = 132.0)
source
JuliaGrid.updateBus!Function
updateBus!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing bus.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific bus, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBus! function, along with their respective values. Ensure that the label keyword matches the label of the existing bus you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the bus field within the PowerSystem composite type, and in cases where parameters impact variables in the ac field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBus! function.

Example

system = powerSystem()
+addBus!(system; label = "Bus 1", active = 25.0, angle = 10.026, base = 132.0)
source
JuliaGrid.updateBus!Function
updateBus!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing bus.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.

Keywords

To update a specific bus, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBus! function, along with their respective values. Ensure that the label keyword matches the label of the existing bus you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the bus field within the PowerSystem composite type, and in cases where parameters impact variables in the ac field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBus! function.

Example

system = powerSystem()
 
 addBus!(system; label = "Bus 1", type = 3, active = 0.25, reactive = -0.04)
-updateBus!(system; label = "Bus 1", active = 0.15, susceptance = 0.15)
source
JuliaGrid.@busMacro
@bus(kwargs...)

The macro generates a template for a bus, which can be utilized to define a bus using the addBus! function.

Keywords

To define the bus template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBus! function, along with their corresponding values.

Units

By default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.

Examples

Adding a bus template using the default unit system:

system = powerSystem()
+updateBus!(system; label = "Bus 1", active = 0.15, susceptance = 0.15)
source
JuliaGrid.@busMacro
@bus(kwargs...)

The macro generates a template for a bus, which can be utilized to define a bus using the addBus! function.

Keywords

To define the bus template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBus! function, along with their corresponding values.

Units

By default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.

Examples

Adding a bus template using the default unit system:

system = powerSystem()
 
 @bus(type = 2, active = 0.25, angle = 0.1745)
 addBus!(system; label = "Bus 1", reactive = -0.04, base = 132e3)

Adding a bus template using a custom unit system:

@power(MW, MVAr, MVA)
@@ -20,7 +20,7 @@
 system = powerSystem()
 
 @bus(type = 2, active = 25.0, angle = 10.0, base = 132.0)
-addBus!(system; label = "Bus 1", reactive = -4.0)
source

Branch

JuliaGrid.addBranch!Function
addBranch!(system::PowerSystem, [analysis::Analysis]; label, from, to, status,
+addBus!(system; label = "Bus 1", reactive = -4.0)
source

Branch

JuliaGrid.addBranch!Function
addBranch!(system::PowerSystem, [analysis::Analysis]; label, from, to, status,
     resistance, reactance, conductance, susceptance, turnsRatio, shiftAngle,
     minDiffAngle, maxDiffAngle, minFromBus, maxFromBus, minToBus, maxToBus, type)

The function adds a new branch to the PowerSystem composite type. A branch can be added between already defined buses.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.

Keywords

The branch is defined with the following keywords:

  • label: Unique label for the branch.
  • from: From-bus label, corresponds to the bus label.
  • to: To-bus label, corresponds to the bus label.
  • status: Operating status of the branch:
    • status = 1: in-service,
    • status = 0: out-of-service.
  • resistance (pu or Ω): Series resistance.
  • reactance (pu or Ω): Series reactance.
  • conductance (pu or S): Total shunt conductance.
  • susceptance (pu or S): Total shunt susceptance.
  • turnsRatio: Transformer off-nominal turns ratio, equal to one for a line.
  • shiftAngle (rad or deg): Transformer phase shift angle, where positive value defines delay.
  • minDiffAngle (rad or deg): Minimum voltage angle difference value between from-bus and to-bus ends.
  • maxDiffAngle (rad or deg): Maximum voltage angle difference value between from-bus and to-bus ends.
  • minFromBus (pu, VA, W, or A): Minimum branch flow rating at the from-bus end.
  • maxFromBus (pu, VA, W, or A): Maximum branch flow rating at the from-bus end.
  • minToBus (pu, VA, W, or A): Minimum branch flow rating at the to-bus end.
  • maxToBus (pu, VA, W, or A): Maximum branch flow rating at the to-bus end.
  • type: Types of minFromBus, maxFromBus, minToBus, and maxToBus branch flow ratings:
    • type = 1: apparent power flow (pu or VA),
    • type = 2: active power flow (pu or W),
    • type = 3: current magnitude flow (pu or A).

Updates

The function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Default Settings

By default, certain keywords are assigned default values: status = 1, turnsRatio = 1.0, type = 1, minDiffAngle = -2pi, and maxDiffAngle = 2pi. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @branch macro.

Units

The default units for the keyword parameters are per-units (pu) and radians (rad). However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, @current, and @parameter.

Examples

Adding a branch using the default unit system:

system = powerSystem()
 
@@ -33,13 +33,13 @@
 addBus!(system; label = "Bus 1", type = 3, active = 0.25, reactive = -0.04)
 addBus!(system; label = "Bus 2", type = 1, active = 0.15, reactive = 0.08)
 
-addBranch!(system; from = "Bus 1", to = "Bus 2", reactance = 0.12, shiftAngle = 10)
source
JuliaGrid.updateBranch!Function
updateBranch!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing branch.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter

Keywords

To update a specific branch, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBranch! function, along with their respective values. Ensure that the label keyword matches the label of the existing branch you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBranch! function.

Example

system = powerSystem()
+addBranch!(system; from = "Bus 1", to = "Bus 2", reactance = 0.12, shiftAngle = 10)
source
JuliaGrid.updateBranch!Function
updateBranch!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing branch.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter

Keywords

To update a specific branch, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBranch! function, along with their respective values. Ensure that the label keyword matches the label of the existing branch you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBranch! function.

Example

system = powerSystem()
 
 addBus!(system; label = "Bus 1", type = 3, active = 0.25, reactive = -0.04)
 addBus!(system; label = "Bus 2", type = 1, active = 0.15, reactive = 0.08)
 
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.12)
-updateBranch!(system; label = "Branch 1", reactance = 0.02, susceptance = 0.062)
source
JuliaGrid.@branchMacro
@branch(kwargs...)

The macro generates a template for a branch, which can be utilized to define a branch using the addBranch! function.

Keywords

To define the branch template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBranch! function, along with their corresponding values.

Units

The default units for the keyword parameters are per-units and radians. However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, and @parameter.

Examples

Adding a branch template using the default unit system:

system = powerSystem()
+updateBranch!(system; label = "Branch 1", reactance = 0.02, susceptance = 0.062)
source
JuliaGrid.@branchMacro
@branch(kwargs...)

The macro generates a template for a branch, which can be utilized to define a branch using the addBranch! function.

Keywords

To define the branch template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBranch! function, along with their corresponding values.

Units

The default units for the keyword parameters are per-units and radians. However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, and @parameter.

Examples

Adding a branch template using the default unit system:

system = powerSystem()
 
 addBus!(system; label = "Bus 1", type = 3, active = 0.25, reactive = -0.04)
 addBus!(system; label = "Bus 2", type = 1, active = 0.15, reactive = 0.08)
@@ -52,7 +52,7 @@
 addBus!(system; label = "Bus 2", type = 1,  active = 0.15, reactive = 0.08)
 
 @branch(shiftAngle = 10)
-addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.12)
source

Generator

JuliaGrid.addGenerator!Function
addGenerator!(system::PowerSystem, [analysis::Analysis]; label, bus, status,
+addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.12)
source

Generator

JuliaGrid.addGenerator!Function
addGenerator!(system::PowerSystem, [analysis::Analysis]; label, bus, status,
     active, reactive, magnitude, minActive, maxActive, minReactive, maxReactive,
     lowActive, minLowReactive, maxLowReactive, upActive, minUpReactive, maxUpReactive,
     loadFollowing, reactiveRamp, reserve10min, reserve30min, area)

The function adds a new generator to the PowerSystem composite type. The generator can be added to an already defined bus.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new generator.

Keywords

The generator is defined with the following keywords:

  • label: Unique label for the generator.
  • bus: Label of the bus to which the generator is connected.
  • status: Operating status of the generator:
    • status = 1: in-service,
    • status = 0: out-of-service.
  • active (pu or W): Output active power.
  • reactive (pu or VAr): Output reactive power.
  • magnitude (pu or V): Voltage magnitude setpoint.
  • minActive (pu or W): Minimum allowed output active power value.
  • maxActive (pu or W): Maximum allowed output active power value.
  • minReactive (pu or VAr): Minimum allowed output reactive power value.
  • maxReactive (pu or VAr): Maximum allowed output reactive power value.
  • lowActive (pu or W): Lower allowed active power output value of PQ capability curve.
  • minLowReactive (pu or VAr): Minimum allowed reactive power output value at lowActive value.
  • maxLowReactive (pu or VAr): Maximum allowed reactive power output value at lowActive value.
  • upActive (pu or W): Upper allowed active power output value of PQ capability curve.
  • minUpReactive (pu or VAr): Minimum allowed reactive power output value at upActive value.
  • maxUpReactive (pu or VAr): Maximum allowed reactive power output value at upActive value.
  • loadFollowing (pu/min or W/min): Ramp rate for load following/AG.
  • reserve10min (pu or W): Ramp rate for 10-minute reserves.
  • reserve30min (pu or W): Ramp rate for 30-minute reserves.
  • reactiveRamp (pu/min or VAr/min): Ramp rate for reactive power, two seconds timescale.
  • area: Area participation factor.

Updates

The function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Default Settings

By default, certain keywords are assigned default values: status = 1 and magnitude = 1.0 per-unit. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @generator macro.

Units

By default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.

Examples

Adding a generator using the default unit system:

system = powerSystem()
@@ -65,12 +65,12 @@
 
 addBus!(system; label = "Bus 1", type = 2, active = 20, base = 132)
 
-addGenerator!(system; bus = "Bus 1", active = 50, magnitude = 145.2)
source
JuliaGrid.updateGenerator!Function
updateGenerator!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing generator.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter

Keywords

To update a specific generator, provide the necessary kwargs input arguments in accordance with the keywords specified in the addGenerator! function, along with their respective values. Ensure that the label keyword matches the label of the existing generator you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBranch! function.

Example

system = powerSystem()
+addGenerator!(system; bus = "Bus 1", active = 50, magnitude = 145.2)
source
JuliaGrid.updateGenerator!Function
updateGenerator!(system::PowerSystem, [analysis::Analysis]; kwargs...)

The function allows for the alteration of parameters for an existing generator.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter

Keywords

To update a specific generator, provide the necessary kwargs input arguments in accordance with the keywords specified in the addGenerator! function, along with their respective values. Ensure that the label keyword matches the label of the existing generator you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.

Updates

The function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

Units for input parameters can be changed using the same method as described for the addBranch! function.

Example

system = powerSystem()
 
 addBus!(system; label = "Bus 1", type = 2, active = 0.2, base = 132e3)
 
 addGenerator!(system; label = "Generator 1", bus = "Bus 1", active = 0.5)
-updateGenerator!(system; label = "Generator 1", active = 0.6, reactive = 0.2)
source
JuliaGrid.cost!Function
cost!(system::PowerSystem, [analysis::Analysis]; label, active, reactive,
+updateGenerator!(system; label = "Generator 1", active = 0.6, reactive = 0.2)
source
JuliaGrid.cost!Function
cost!(system::PowerSystem, [analysis::Analysis]; label, active, reactive,
     piecewise, polynomial)

The function either adds a new cost or modifies an existing one for the active or reactive power generated by the corresponding generator within the PowerSystem composite type. It has the capability to append a cost to an already defined generator.

Arguments

If the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.

Keywords

The function accepts five keywords:

  • label: Corresponds to the already defined generator label.
  • active: Active power cost model:
    • active = 1: adding or updating cost, and piecewise linear is being used,
    • active = 2: adding or updating cost, and polynomial is being used.
  • reactive: Reactive power cost model:
    • reactive = 1: adding or updating cost, and piecewise linear is being used,
    • reactive = 2: adding or updating cost, and polynomial is being used.
  • piecewise: Cost model defined by input-output points given as Matrix{Float64}:
    • first column (pu, W or VAr): active or reactive power output of the generator,
    • second column (€/hr): cost for the specified active or reactive power output.
  • polynomial: The n-th degree polynomial coefficients given as Vector{Float64}:
    • first element (€/puⁿ-hr, €/Wⁿhr or €/VArⁿ-hr): coefficient of the n-th degree term, ....,
    • penultimate element (€/pu-hr, €/W-hr or €/VAr-hr): coefficient of the first degree term,
    • last element (€/hr): constant coefficient.

Updates

The function updates the generator.cost field within the PowerSystem composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.

Units

By default, the input units related with active powers are per-units (pu), but they can be modified using the macro @power.

Examples

Adding a cost using the default unit system:

system = powerSystem()
 
 addBus!(system; label = "Bus 1", active = 0.25, reactive = -0.04, base = 132e3)
@@ -82,7 +82,7 @@
 addBus!(system; label = "Bus 1", active = 25, reactive = -4, base = 132e3)
 
 addGenerator!(system; label = "Generator 1", bus = "Bus 1", active = 50, reactive = 10)
-cost!(system; label = "Generator 1", active = 2, polynomial = [0.11; 5.0; 150.0])
source
JuliaGrid.@generatorMacro
@generator(kwargs...)

The macro generates a template for a generator, which can be utilized to define a generator using the addGenerator! function.

Keywords

To define the generator template, the kwargs input arguments must be provided in accordance with the keywords specified within the addGenerator! function, along with their corresponding values.

Units

By default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.

Examples

Adding a generator using the default unit system:

system = powerSystem()
+cost!(system; label = "Generator 1", active = 2, polynomial = [0.11; 5.0; 150.0])
source
JuliaGrid.@generatorMacro
@generator(kwargs...)

The macro generates a template for a generator, which can be utilized to define a generator using the addGenerator! function.

Keywords

To define the generator template, the kwargs input arguments must be provided in accordance with the keywords specified within the addGenerator! function, along with their corresponding values.

Units

By default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.

Examples

Adding a generator using the default unit system:

system = powerSystem()
 
 addBus!(system; label = "Bus 1", type = 2, active = 0.25, reactive = -0.04, base = 132e3)
 
@@ -94,4 +94,4 @@
 addBus!(system; label = "Bus 1", type = 2, active = 25, reactive = -4, base = 132)
 
 @generator(magnitude = 145.2)
-addGenerator!(system; label = "Generator 1", bus = "Bus 1", active = 50, reactive = 10)
source
+addGenerator!(system; label = "Generator 1", bus = "Bus 1", active = 50, reactive = 10)
source
diff --git a/dev/api/setupPrint/index.html b/dev/api/setupPrint/index.html index 28897a22..cef860f8 100644 --- a/dev/api/setupPrint/index.html +++ b/dev/api/setupPrint/index.html @@ -1,6 +1,6 @@ Setup and Print · JuliaGrid

Setup and Print

For further information on this topic, please see the Power System Model or Measurement Model sections of the Manual. Please note that when using macros, they modify variables within the current scope. Print functions can be used to print results to the REPL, or users can redirect the output to print results to a text file, for example.

To load power system model API functionalities into the current scope, utilize the following command:

using JuliaGrid

Base Units
Input Units
Label Types
Default Settings

Base Units

JuliaGrid.@baseMacro
@base(system::PowerSystem, power, voltage)

By default, the units for base power and base voltages are set to volt-ampere (VA) and volt (V), but you can modify the prefixes using the macro.

Prefixes must be specified according to the SI prefixes and should be included with the unit of power (VA) or unit of voltage (V). Keep in mind that the macro must be used after creating the composite type PowerSystem.

Example

system = powerSystem("case14.h5")
-@base(system, MVA, kV)
source

Input Units

JuliaGrid.@powerMacro
@power(active, reactive, apparent)

JuliaGrid stores all data related with powers in per-units, and these cannot be altered. However, the power units of the built-in functions used to add or modified power system elements can be modified using the macro.

Prefixes must be specified according to the SI prefixes and should be included with the unit of active power (W), reactive power (VAr), or apparent power (VA). Also, it is a possible to combine SI units with/without prefixes with per-units (pu).

Changing the unit of active power is reflected in the following quantities:

Changing the unit of reactive power unit is reflected in the following quantities:

Changing the unit of apparent power unit is reflected in the following quantities:

Example

@power(MW, kVAr, VA)
source
JuliaGrid.@voltageMacro
@voltage(magnitude, angle, base)

JuliaGrid stores all data related with voltages in per-units and radians, and these cannot be altered. However, the voltage magnitude and angle units of the built-in functions used to add or modified power system elements can be modified using the macro.

The prefixes must adhere to the SI prefixes and should be specified along with the unit of voltage, either magnitude (V) or base (V). Alternatively, the unit of voltage magnitude can be expressed in per-unit (pu). The unit of voltage angle should be in radians (rad) or degrees (deg).

Changing the unit of voltage magnitude is reflected in the following quantities:

Changing the unit of voltage angle is reflected in the following quantities:

Changing the unit prefix of voltage base is reflected in the following quantity:

Example

@voltage(pu, deg, kV)
source
JuliaGrid.@currentMacro
@current(magnitude, angle)

JuliaGrid stores all data related with currents in per-units and radians, and these cannot be altered. However, the current magnitude and angle units of the built-in functions used to add or modified measurement devices can be modified using the macro.

The prefixes must adhere to the SI prefixes and should be specified along with the unit of current magnitude (V). Alternatively, the unit of current magnitude can be expressed in per-unit (pu). The unit of current angle should be in radians (rad) or degrees (deg).

Changing the unit of current magnitude is reflected in the following quantities:

Changing the unit of current angle is reflected in the following quantities:

Example

@current(pu, deg)
source
JuliaGrid.@parameterMacro
@parameter(impedance, admittance)

JuliaGrid stores all data related with impedances and admittancies in per-units, and these cannot be altered. However, units of impedance and admittance of the built-in functions used to add or modified power system elements can be modified using the macro.

Prefixes must be specified according to the SI prefixes and should be included with the unit of impedance (Ω) or unit of admittance (S). The second option is to define the units in per-unit (pu).

In the case where impedance and admittance are being used in SI units (Ω and S) and these units are related to the transformer, the assignment must be based on the primary side of the transformer.

Changing the units of impedance is reflected in the following quantities in specific functions:

Changing the units of admittance is reflected in the following quantities:

Example

@parameter(Ω, pu)
source

Label Types

JuliaGrid.@labelsMacro
@labels(type)

JuliaGrid keeps all labels in ordered dictionaries as Strings. Users have the option to use Integers instead, which can be a more efficient way to store labels, particularly for large-scale systems.

Example

@labels(Integer)
source

Default Settings

JuliaGrid.@defaultMacro
@default(mode)

The macro is designed to reset various settings to their default values.

The mode argument can take on the following values:

  • unit: Resets all units to their default settings.
  • power: Sets active, reactive, and apparent power to per-units.
  • voltage: Sets voltage magnitude to per-unit and voltage angle to radian.
  • parameter: Sets impedance and admittance to per-units.
  • template: Resets bus, branch, generator, voltmeter, ammeter, wattmeter, varmeter, and pmu templates to their default settings.
  • bus: Resets the bus template to its default settings.
  • branch: Resets the branch template to its default settings.
  • generator: Resets the generator template to its default settings.
  • voltmeter: Resets the voltmeter template to its default settings.
  • ammeter: Resets the ammeter template to its default settings.
  • wattmeter: Resets the wattmeter template to its default settings.
  • varmeter: Resets the varmeter template to its default settings.
  • pmu: Resets the pmu template to its default settings.

Example

@default(unit)
source

Print Power System Data


Input Units

JuliaGrid.@powerMacro
@power(active, reactive, apparent)

JuliaGrid stores all data related with powers in per-units, and these cannot be altered. However, the power units of the built-in functions used to add or modified power system elements can be modified using the macro.

Prefixes must be specified according to the SI prefixes and should be included with the unit of active power (W), reactive power (VAr), or apparent power (VA). Also, it is a possible to combine SI units with/without prefixes with per-units (pu).

Changing the unit of active power is reflected in the following quantities:

Changing the unit of reactive power unit is reflected in the following quantities:

Changing the unit of apparent power unit is reflected in the following quantities:

Example

@power(MW, kVAr, VA)
source
JuliaGrid.@voltageMacro
@voltage(magnitude, angle, base)

JuliaGrid stores all data related with voltages in per-units and radians, and these cannot be altered. However, the voltage magnitude and angle units of the built-in functions used to add or modified power system elements can be modified using the macro.

The prefixes must adhere to the SI prefixes and should be specified along with the unit of voltage, either magnitude (V) or base (V). Alternatively, the unit of voltage magnitude can be expressed in per-unit (pu). The unit of voltage angle should be in radians (rad) or degrees (deg).

Changing the unit of voltage magnitude is reflected in the following quantities:

Changing the unit of voltage angle is reflected in the following quantities:

Changing the unit prefix of voltage base is reflected in the following quantity:

Example

@voltage(pu, deg, kV)
source
JuliaGrid.@currentMacro
@current(magnitude, angle)

JuliaGrid stores all data related with currents in per-units and radians, and these cannot be altered. However, the current magnitude and angle units of the built-in functions used to add or modified measurement devices can be modified using the macro.

The prefixes must adhere to the SI prefixes and should be specified along with the unit of current magnitude (V). Alternatively, the unit of current magnitude can be expressed in per-unit (pu). The unit of current angle should be in radians (rad) or degrees (deg).

Changing the unit of current magnitude is reflected in the following quantities:

Changing the unit of current angle is reflected in the following quantities:

Example

@current(pu, deg)
source
JuliaGrid.@parameterMacro
@parameter(impedance, admittance)

JuliaGrid stores all data related with impedances and admittancies in per-units, and these cannot be altered. However, units of impedance and admittance of the built-in functions used to add or modified power system elements can be modified using the macro.

Prefixes must be specified according to the SI prefixes and should be included with the unit of impedance (Ω) or unit of admittance (S). The second option is to define the units in per-unit (pu).

In the case where impedance and admittance are being used in SI units (Ω and S) and these units are related to the transformer, the assignment must be based on the primary side of the transformer.

Changing the units of impedance is reflected in the following quantities in specific functions:

Changing the units of admittance is reflected in the following quantities:

Example

@parameter(Ω, pu)
source

Label Types

JuliaGrid.@labelsMacro
@labels(type)

JuliaGrid keeps all labels in ordered dictionaries as Strings. Users have the option to use Integers instead, which can be a more efficient way to store labels, particularly for large-scale systems.

Example

@labels(Integer)
source

Default Settings

JuliaGrid.@defaultMacro
@default(mode)

The macro is designed to reset various settings to their default values.

The mode argument can take on the following values:

  • unit: Resets all units to their default settings.
  • power: Sets active, reactive, and apparent power to per-units.
  • voltage: Sets voltage magnitude to per-unit and voltage angle to radian.
  • parameter: Sets impedance and admittance to per-units.
  • template: Resets bus, branch, generator, voltmeter, ammeter, wattmeter, varmeter, and pmu templates to their default settings.
  • bus: Resets the bus template to its default settings.
  • branch: Resets the branch template to its default settings.
  • generator: Resets the generator template to its default settings.
  • voltmeter: Resets the voltmeter template to its default settings.
  • ammeter: Resets the ammeter template to its default settings.
  • wattmeter: Resets the wattmeter template to its default settings.
  • varmeter: Resets the varmeter template to its default settings.
  • pmu: Resets the pmu template to its default settings.

Example

@default(unit)
source

Print Power System Data

JuliaGrid.printBusDataFunction
printBusData(system::PowerSystem, analysis::Analysis, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints voltages, powers, and currents related to buses. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding bus.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -24,7 +24,7 @@
 printBusData(system, analysis; label = 2, delimiter, width, title = true, header = true)
 printBusData(system, analysis; label = 10, delimiter, width)
 printBusData(system, analysis; label = 12, delimiter, width)
-printBusData(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printBranchDataFunction
printBranchData(system::PowerSystem, analysis::Analysis, [io::IO];
+printBusData(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printBranchDataFunction
printBranchData(system::PowerSystem, analysis::Analysis, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints powers and currents related to branches. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding branch.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBranchData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -48,7 +48,7 @@
 printBranchData(system, analysis; label = 2, delimiter, width, header = true)
 printBranchData(system, analysis; label = 10, delimiter, width)
 printBranchData(system, analysis; label = 12, delimiter, width)
-printBranchData(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printGeneratorDataFunction
printGeneratorData(system::PowerSystem, analysis::Analysis, [io::IO];
+printBranchData(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printGeneratorDataFunction
printGeneratorData(system::PowerSystem, analysis::Analysis, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints powers related to generators. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding generator.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printGeneratorData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -71,7 +71,7 @@
 width = Dict("Power Output Active" => 7)
 printGeneratorData(system, analysis; label = 1, delimiter, width, header = true)
 printGeneratorData(system, analysis; label = 4, delimiter, width)
-printGeneratorData(system, analysis; label = 5, delimiter, width, footer = true)
source

Print Power System Summary

JuliaGrid.printBusSummaryFunction
printBusSummary(system::PowerSystem, analysis::Analysis, [io::IO];
+printGeneratorData(system, analysis; label = 5, delimiter, width, footer = true)
source

Print Power System Summary

JuliaGrid.printBusSummaryFunction
printBusSummary(system::PowerSystem, analysis::Analysis, [io::IO];
     fmt, width, show, delimiter, title, header, footer, style)

The function prints a summary of the electrical quantities related to buses. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusSummary requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -85,7 +85,7 @@
 power!(system, analysis)
 
 show = Dict("In-Use" => false)
-printBusSummary(system, analysis; show, delimiter = " ", title = false)
source
JuliaGrid.printBranchSummaryFunction
printBranchSummary(system::PowerSystem, analysis::Analysis, [io::IO];
+printBusSummary(system, analysis; show, delimiter = " ", title = false)
source
JuliaGrid.printBranchSummaryFunction
printBranchSummary(system::PowerSystem, analysis::Analysis, [io::IO];
     fmt, width, show, delimiter, title, header, footer, style))

The function prints a summary of the electrical quantities related to branches. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBranchSummary requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -99,7 +99,7 @@
 power!(system, analysis)
 
 show = Dict("Total" => false)
-printBranchSummary(system, analysis; show, delimiter = " ", title = false)
source
JuliaGrid.printGeneratorSummaryFunction
printGeneratorSummary(system::PowerSystem, analysis::Analysis, [io::IO];
+printBranchSummary(system, analysis; show, delimiter = " ", title = false)
source
JuliaGrid.printGeneratorSummaryFunction
printGeneratorSummary(system::PowerSystem, analysis::Analysis, [io::IO];
     fmt, width, show, delimiter, title, header, footer, style)

The function prints a summary of the electrical quantities related to generators. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printGeneratorSummary requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 
 analysis = newtonRaphson(system)
@@ -113,7 +113,7 @@
 power!(system, analysis)
 
 show = Dict("Minimum" => false)
-printGeneratorSummary(system, analysis; show, delimiter = " ", title = false)
source

JuliaGrid.printVoltmeterDataFunction
printVoltmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
+printGeneratorSummary(system, analysis; show, delimiter = " ", title = false)
source

JuliaGrid.printVoltmeterDataFunction
printVoltmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
     [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints data related to voltmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding voltmeter.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -135,7 +135,7 @@
 width = Dict("Voltage Magnitude Estimate" => 11)
 printVoltmeterData(system, device, analysis; label = 1, width, header = true)
 printVoltmeterData(system, device, analysis; label = 6, width)
-printVoltmeterData(system, device, analysis; label = 8, width, footer = true)
source
JuliaGrid.printAmmeterDataFunction
printAmmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
+printVoltmeterData(system, device, analysis; label = 8, width, footer = true)
source
JuliaGrid.printAmmeterDataFunction
printAmmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
     [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints data related to ammeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding ammeter.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -157,7 +157,7 @@
 width = Dict("Current Magnitude" => 10)
 printAmmeterData(system, device, analysis; label = "From 1", width, header = true)
 printAmmeterData(system, device, analysis; label = "From 4", width)
-printAmmeterData(system, device, analysis; label = "From 6", width, footer = true)
source
JuliaGrid.printWattmeterDataFunction
printWattmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
+printAmmeterData(system, device, analysis; label = "From 6", width, footer = true)
source
JuliaGrid.printWattmeterDataFunction
printWattmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
     [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints data related to wattmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding wattmeter.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -179,7 +179,7 @@
 width = Dict("Active Power Residual" => 11)
 printWattmeterData(system, device, analysis; label = 2, width, header = true)
 printWattmeterData(system, device, analysis; label = 5, width)
-printWattmeterData(system, device, analysis; label = 9, width, footer = true)
source
JuliaGrid.printVarmeterDataFunction
printVarmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
+printWattmeterData(system, device, analysis; label = 9, width, footer = true)
source
JuliaGrid.printVarmeterDataFunction
printVarmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],
     [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints data related to varmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding varmeter.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -201,7 +201,7 @@
 width = Dict("Reactive Power Residual" => 11)
 printVarmeterData(system, device, analysis; label = 2, width, header = true)
 printVarmeterData(system, device, analysis; label = 5, width)
-printVarmeterData(system, device, analysis; label = 9, width, footer = true)
source
JuliaGrid.printPmuDataFunction
printPmuData(system::PowerSystem, device::Measurement, [analysis::Analysis],
+printVarmeterData(system, device, analysis; label = 9, width, footer = true)
source
JuliaGrid.printPmuDataFunction
printPmuData(system::PowerSystem, device::Measurement, [analysis::Analysis],
     [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints data related to PMUs. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding PMU.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printPmuData requires Julia 1.10 or later.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -223,7 +223,7 @@
 width = Dict("Current Magnitude" => 10, "Current Angle Status" => 8)
 printPmuData(system, device, analysis; label = "From 1", width, header = true)
 printPmuData(system, device, analysis; label = "From 4", width)
-printPmuData(system, device, analysis; label = "From 6", width, footer = true)
source

Print Constraint Data

JuliaGrid.printBusConstraintFunction
printBusConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
+printPmuData(system, device, analysis; label = "From 6", width, footer = true)
source

Print Constraint Data

JuliaGrid.printBusConstraintFunction
printBusConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints constraint data related to buses. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding bus.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBusConstraint requires Julia 1.10 or later.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
@@ -241,7 +241,7 @@
 width = Dict("Voltage Magnitude" => 8, "Active Power Balance Solution" => 12)
 printBusConstraint(system, analysis; label = 2, delimiter, width, header = true)
 printBusConstraint(system, analysis; label = 10, delimiter, width)
-printBusConstraint(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printBranchConstraintFunction
printBranchConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
+printBusConstraint(system, analysis; label = 14, delimiter, width, footer = true)
source
JuliaGrid.printBranchConstraintFunction
printBranchConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints constraint data related to branches. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding branch.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printBranchConstraint requires Julia 1.10 or later.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
@@ -263,7 +263,7 @@
 width = Dict("From-Bus Apparent Power Flow" => 13, "Voltage Angle Difference Dual" => 12)
 printBranchConstraint(system, analysis; label = 3, delimiter, width, header = true)
 printBranchConstraint(system, analysis; label = 4, delimiter, width)
-printBranchConstraint(system, analysis; label = 9, delimiter, width, footer = true)
source
JuliaGrid.printGeneratorConstraintFunction
printGeneratorConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
+printBranchConstraint(system, analysis; label = 9, delimiter, width, footer = true)
source
JuliaGrid.printGeneratorConstraintFunction
printGeneratorConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];
     label, fmt, width, show, delimiter, title, header, footer, repeat, style)

The function prints constraint data related to generators. Optionally, an IO may be passed as the last argument to redirect the output.

Keywords

The following keywords control the printed data:

  • label: Prints only the data for the corresponding generator.
  • fmt: Specifies the preferred numeric formats or alignments for the columns.
  • width: Specifies the preferred widths for the columns.
  • show: Toggles the printing of the columns.
  • delimiter: Sets the column delimiter.
  • title: Toggles the printing of the table title.
  • header: Toggles the printing of the header.
  • footer: Toggles the printing of the footer.
  • repeat: Prints the header again after a specified number of lines have been printed.
  • style: Prints either a stylish table or a simple table suitable for easy export.
Julia 1.10

The function printGeneratorConstraint requires Julia 1.10 or later.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
@@ -281,4 +281,4 @@
 width = Dict("Active Power Capability" => 11, "Reactive Power Capability Dual" => 10)
 printGeneratorConstraint(system, analysis; label = 2, delimiter, width, header = true)
 printGeneratorConstraint(system, analysis; label = 3, delimiter, width)
-printGeneratorConstraint(system, analysis; label = 5, delimiter, width, footer = true)
source
+printGeneratorConstraint(system, analysis; label = 5, delimiter, width, footer = true)source diff --git a/dev/api/stateEstimation/index.html b/dev/api/stateEstimation/index.html index 72806bd9..2044aefd 100644 --- a/dev/api/stateEstimation/index.html +++ b/dev/api/stateEstimation/index.html @@ -5,13 +5,13 @@ statusWattmeter!(system, device; inservice = 15) device.varmeter.reactive.status = copy(device.wattmeter.active.status) -islands = islandTopologicalFlow(system, device)source
JuliaGrid.islandTopologicalMethod
islandTopological(system::PowerSystem, meter::Measurement)

The function employs a topological method to identify maximal observable islands. Specifically, it employs active power measurements to pinpoint flow observable islands. Subsequently, these islands are merged based on the available injection measurements.

It is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.

Arguments

To define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.

Returns

The function returns an Island type, containing information about the islands:

  • island: List enumerating observable islands with indices of buses.
  • bus: Positions of buses in relation to each island.
  • tie: Tie data associated with buses and branches.

Example

system = powerSystem("case14.h5")
+islands = islandTopologicalFlow(system, device)
source
JuliaGrid.islandTopologicalMethod
islandTopological(system::PowerSystem, meter::Measurement)

The function employs a topological method to identify maximal observable islands. Specifically, it employs active power measurements to pinpoint flow observable islands. Subsequently, these islands are merged based on the available injection measurements.

It is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.

Arguments

To define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.

Returns

The function returns an Island type, containing information about the islands:

  • island: List enumerating observable islands with indices of buses.
  • bus: Positions of buses in relation to each island.
  • tie: Tie data associated with buses and branches.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 statusWattmeter!(system, device; inservice = 15)
 device.varmeter.reactive.status = copy(device.wattmeter.active.status)
 
-islands = islandTopological(system, device)
source
JuliaGrid.restorationGram!Method
restorationGram!(system::PowerSystem, device::Measurement, pseudo::Measurement,
+islands = islandTopological(system, device)
source
JuliaGrid.restorationGram!Method
restorationGram!(system::PowerSystem, device::Measurement, pseudo::Measurement,
     islands::Island; threshold)

Upon identifying the islands, the function incorporates measurements from the available pseudo-measurements in the pseudo variable into the device variable to reinstate observability. This method relies on reduced coefficient matrices and the Gram matrix.

It is important to note that the device labels in the device and pseudo variables must be different to enable the function to successfully incorporate measurements from pseudo into the device set of measurements.

Keyword

The keyword threshold defines the zero pivot threshold value, with a default value of 1e-5. More precisely, all computed pivots less than this value will be treated as zero pivots.

Updates

The function updates the device variable of the Measurement composite type.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 pseudo = measurement("pseudomeasurement14.h5")
@@ -19,18 +19,18 @@
 statusWattmeter!(system, device; inservice = 10)
 islands = islandTopological(system, device)
 
-restorationGram!(system, device, pseudo, islands)
source

AC State Estimation

JuliaGrid.gaussNewtonFunction
gaussNewton(system::PowerSystem, device::Measurement, [method = LU])

The function sets up the Gauss-Newton method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates. The Gauss-Newton method throughout iterations provided WLS estimator.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the nonlinear WLS state estimation framework.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the ACStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The system model vectors and matrices.

Examples

Set up the AC state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
+restorationGram!(system, device, pseudo, islands)
source

AC State Estimation

JuliaGrid.gaussNewtonFunction
gaussNewton(system::PowerSystem, device::Measurement, [method = LU])

The function sets up the Gauss-Newton method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates. The Gauss-Newton method throughout iterations provided WLS estimator.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the nonlinear WLS state estimation framework.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the ACStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The system model vectors and matrices.

Examples

Set up the AC state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = gaussNewton(system, device)

Set up the AC state estimation model to be solved using the orthogonal method:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = gaussNewton(system, device, Orthogonal)
source
JuliaGrid.acLavStateEstimationFunction
acLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function sets up the LAV method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the ACStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The optimization model.

Example

using Ipopt
+analysis = gaussNewton(system, device, Orthogonal)
source
JuliaGrid.acLavStateEstimationFunction
acLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function sets up the LAV method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the ACStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The optimization model.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = acLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACStateEstimation)

By computing the bus voltage magnitudes and angles, the function solves the AC state estimation model.

Updates

The resulting bus voltage magnitudes and angles are stored in the voltage field of the ACStateEstimation type.

Examples

Solving the AC state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
+analysis = acLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::ACStateEstimation)

By computing the bus voltage magnitudes and angles, the function solves the AC state estimation model.

Updates

The resulting bus voltage magnitudes and angles are stored in the voltage field of the ACStateEstimation type.

Examples

Solving the AC state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = gaussNewton(system, device)
@@ -45,7 +45,7 @@
 device = measurement("measurement14.h5")
 
 analysis = acLavStateEstimation(system, device, Ipopt.Optimizer)
-solve!(system, analysis)
source

PMU State Estimation

JuliaGrid.pmuPlacementFunction
pmuPlacement(system::PowerSystem, optimizer; bridge)

The function determines the optimal placement of PMUs through integer linear programming. Specifically, it identifies the minimum set of PMU locations required for effective power system state estimation, ensuring observability with the least number of PMUs.

The function accepts a PowerSystem composite type as input to establish the framework for finding the optimal PMU placement. If the ac field within the PowerSystem composite type is not yet created, the function automatically initiates an update process.

Additionally, the optimizer argument is a crucial component for formulating and solving the optimization problem. Typically, using the GLPK or HiGHS solver is sufficient. For more detailed information, please refer to the JuMP documenatation.

Keyword

The bridge keyword enables users to manage the bridging mechanism within the JuMP package.

Returns

The function returns an instance of the PlacementPMU type, containing variables such as:

  • bus: Bus labels with indices marking the positions of PMUs at buses.
  • from: Branch labels with indices marking the positions of PMUs at from-bus ends.
  • to: Branch labels with indices marking the positions of PMUs at to-bus ends.

Note that if the conventional understanding of a PMU involves a device measuring the bus voltage phasor and all branch current phasors incident to the bus, the result is saved only in the bus variable. However, if we consider that a PMU measures individual phasors, each described with magnitude and angle, then measurements are needed at each bus in the bus variable, and each branch with positions given according to from and to variables.

Example

using GLPK, Ipopt
+solve!(system, analysis)
source

PMU State Estimation

JuliaGrid.pmuPlacementFunction
pmuPlacement(system::PowerSystem, optimizer; bridge)

The function determines the optimal placement of PMUs through integer linear programming. Specifically, it identifies the minimum set of PMU locations required for effective power system state estimation, ensuring observability with the least number of PMUs.

The function accepts a PowerSystem composite type as input to establish the framework for finding the optimal PMU placement. If the ac field within the PowerSystem composite type is not yet created, the function automatically initiates an update process.

Additionally, the optimizer argument is a crucial component for formulating and solving the optimization problem. Typically, using the GLPK or HiGHS solver is sufficient. For more detailed information, please refer to the JuMP documenatation.

Keyword

The bridge keyword enables users to manage the bridging mechanism within the JuMP package.

Returns

The function returns an instance of the PlacementPMU type, containing variables such as:

  • bus: Bus labels with indices marking the positions of PMUs at buses.
  • from: Branch labels with indices marking the positions of PMUs at from-bus ends.
  • to: Branch labels with indices marking the positions of PMUs at to-bus ends.

Note that if the conventional understanding of a PMU involves a device measuring the bus voltage phasor and all branch current phasors incident to the bus, the result is saved only in the bus variable. However, if we consider that a PMU measures individual phasors, each described with magnitude and angle, then measurements are needed at each bus in the bus variable, and each branch with positions given according to from and to variables.

Example

using GLPK, Ipopt
 
 system = powerSystem("case14.h5")
 device = measurement()
@@ -68,18 +68,18 @@
 for branch in keys(placement.to)
     Iji, ψji = toCurrent(system, analysis; label = branch)
     addPmu!(system, device; to = branch, magnitude = Iji, angle = ψji)
-end
source
JuliaGrid.pmuStateEstimationFunction
pmuStateEstimation(system::PowerSystem, device::Measurement, [method = LU])

The function establishes the linear WLS model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The system model vectors and matrices.

Examples

Set up the PMU state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
+end
source
JuliaGrid.pmuStateEstimationFunction
pmuStateEstimation(system::PowerSystem, device::Measurement, [method = LU])

The function establishes the linear WLS model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The system model vectors and matrices.

Examples

Set up the PMU state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = pmuStateEstimation(system, device)

Set up the PMU state estimation model to be solved using the orthogonal method:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = pmuStateEstimation(system, device, Orthogonal)
source
JuliaGrid.pmuLavStateEstimationFunction
pmuLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function establishes the LAV model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The optimization model.

Example

using Ipopt
+analysis = pmuStateEstimation(system, device, Orthogonal)
source
JuliaGrid.pmuLavStateEstimationFunction
pmuLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function establishes the LAV model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.

Returns

The function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage magnitudes and angles.
  • power: The variable allocated to store the active and reactive powers.
  • method: The optimization model.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::PMUStateEstimation)

By computing the bus voltage magnitudes and angles, the function solves the PMU state estimation model.

Updates

The resulting bus voltage magnitudes and angles are stored in the voltage field of the PMUStateEstimation type.

Examples

Solving the PMU state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
+analysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::PMUStateEstimation)

By computing the bus voltage magnitudes and angles, the function solves the PMU state estimation model.

Updates

The resulting bus voltage magnitudes and angles are stored in the voltage field of the PMUStateEstimation type.

Examples

Solving the PMU state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = pmuStateEstimation(system, device)
@@ -89,18 +89,18 @@
 device = measurement("measurement14.h5")
 
 analysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)
-solve!(system, analysis)
source

DC State Estimation

JuliaGrid.dcStateEstimationFunction
dcStateEstimation(system::PowerSystem, device::Measurement, [method = LU])

The function establishes the WLS model for DC state estimation, where the vector of state variables contains only bus voltage angles.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The system model vectors and matrices.

Examples

Set up the DC state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
+solve!(system, analysis)
source

DC State Estimation

JuliaGrid.dcStateEstimationFunction
dcStateEstimation(system::PowerSystem, device::Measurement, [method = LU])

The function establishes the WLS model for DC state estimation, where the vector of state variables contains only bus voltage angles.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.

Moreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.

If the user does not provide the method, the default method for solving the estimation model will be LU factorization.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCStateEstimation type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The system model vectors and matrices.

Examples

Set up the DC state estimation model to be solved using the default LU factorization:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = dcStateEstimation(system, device)

Set up the DC state estimation model to be solved using the orthogonal method:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = dcStateEstimation(system, device, Orthogonal)
source
JuliaGrid.dcLavStateEstimationFunction
dcLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function establishes the LAV model for DC state estimation, where the vector of state variables contains only bus voltage angles.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The optimization model.

Example

using Ipopt
+analysis = dcStateEstimation(system, device, Orthogonal)
source
JuliaGrid.dcLavStateEstimationFunction
dcLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)

The function establishes the LAV model for DC state estimation, where the vector of state variables contains only bus voltage angles.

Arguments

This function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.

Users can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.

Updates

If the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.

Returns

The function returns an instance of the DCStateEstimation abstract type, which includes the following fields:

  • voltage: The variable allocated to store the bus voltage angles.
  • power: The variable allocated to store the active powers.
  • method: The optimization model.

Example

using Ipopt
 
 system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
-analysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCStateEstimation)

By computing the bus voltage angles, the function solves the DC state estimation model.

Updates

The resulting bus voltage angles are stored in the voltage field of the DCStateEstimation type.

Examples

Solving the DC state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
+analysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)
source
JuliaGrid.solve!Method
solve!(system::PowerSystem, analysis::DCStateEstimation)

By computing the bus voltage angles, the function solves the DC state estimation model.

Updates

The resulting bus voltage angles are stored in the voltage field of the DCStateEstimation type.

Examples

Solving the DC state estimation model and obtaining the WLS estimator:

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
 analysis = dcStateEstimation(system, device)
@@ -110,7 +110,7 @@
 device = measurement("measurement14.h5")
 
 analysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)
-solve!(system, analysis)
source

Bad Data Analysis

JuliaGrid.residualTest!Function
residualTest!(system::PowerSystem, device::Measurement, analysis::StateEstimation;
+solve!(system, analysis)
source

Bad Data Analysis

JuliaGrid.residualTest!Function
residualTest!(system::PowerSystem, device::Measurement, analysis::StateEstimation;
     threshold)

The function conducts bad data detection and identification using the largest normalized residual test, subsequently removing measurement outliers from the measurement set. It can be executed after obtaining WLS estimator.

Arguments

This function requires the types PowerSystem, Measurement, and StateEstimation. The abstract type StateEstimation can have the following subtypes:

  • ACStateEstimation: Conducts bad data analysis within AC state estimation.
  • PMUStateEstimation: Conducts bad data analysis within PMU state estimation.
  • DCStateEstimation: Conducts bad data analysis within DC state estimation.

Keyword

The keyword threshold establishes the identification threshold. If the largest normalized residual surpasses this threshold, the measurement is flagged as bad data. The default threshold value is set to threshold = 3.0.

Updates

If bad data is detected, the function flags the corresponding measurement within the Measurement type as out-of-service.

Moreover, for DCStateEstimation and PMUStateEstimation types, the function removes the corresponding measurement from the coefficient matrix and mean vector. This facilitates direct progress to the function that solves the state estimation problem.

Returns

The function returns an instance of the BadData type, which includes:

  • detect: Returns true after the function's execution if bad data is detected.
  • maxNormalizedResidual: Denotes the value of the largest normalized residual.
  • label: Signifies the label of the bad data.
  • index: Represents the index of the bad data.

Example

system = powerSystem("case14.h5")
 device = measurement("measurement14.h5")
 
@@ -118,4 +118,4 @@
 solve!(system, analysis)
 
 outlier = residualTest!(system, device, analysis; threshold = 4.0)
-solve!(system, analysis)
source
+solve!(system, analysis)source diff --git a/dev/background/bibliography/index.html b/dev/background/bibliography/index.html index c9de1d32..821cfbed 100644 --- a/dev/background/bibliography/index.html +++ b/dev/background/bibliography/index.html @@ -1,2 +1,2 @@ -Bibliography · JuliaGrid

Bibliography

[1]
A. Gomez-Exposito, A. Abur, P. Rousseaux, A. de la Villa Jaen and C. Gomez-Quiles. On the use of PMUs in power system state estimation. In: 17th power system computation conference (2011).
[2]
G. N. Korres. Observability analysis based on Echelon form of a reduced dimensional Jacobian matrix. IEEE Transactions on Power Systems 26, 2572–2573 (2011).
[3]
M. Zhou, V. A. Centeno, J. S. Thorp and A. G. Phadke. An alternative for including phasor measurements in state estimators. IEEE transactions on power systems 21, 1930–1937 (2006).
[4]
G. Korres and N. Manousakis. State estimation and observability analysis for phasor measurement unit measured systems. IET generation, transmission & distribution 6, 902–913 (2012).
[5]
A. Abur and A. G. Exposito. Power system state estimation: theory and implementation (CRC press, 2004).
[6]
G. Andersson. Power system analysis. EEH-Power Systems Laboratory, ETH Zurich, Lecture Notes, 227–0526 (2012).
[7]
J. J. Grainger and W. D. Stevenson. Power system analysis (McGraw-Hill, 1994).
[8]
R. D. Zimmerman and C. E. Murillo-Sánchez. Matpower 6.0 users manual. Power Systems Engineering Research Center 9 (2016).
[9]
A. J. Wood, B. F. Wollenberg and G. B. Sheblé. Power generation, operation, and control (John Wiley & Sons, 2013).
[10]
R. A. Van Amerongen. A general-purpose version of the fast decoupled load flow. IEEE Transactions on Power Systems 4, 760–770 (1989).
[11]
D. P. Chassin, P. R. Armstrong, D. G. Chavarrı́a-Miranda and R. T. Guttromson. Gauss-Seidel accelerated: implementing flow solvers on field programmable gate arrays. In: 2006 IEEE Power Engineering Society General Meeting (IEEE, 2006); p. 5–pp.
[12]
F. C. Schweppe and D. B. Rom. Power system static-state estimation, Part II: Approximate model. IEEE Transactions on Power Apparatus and Systems, 125–130 (1970).
[13]
A. Monticelli. State estimation in electric power systems: a generalized approach (Springer Science & Business Media, 2012).
[14]
A. G. Phadke and J. S. Thorp. Synchronized phasor measurements and their applications. Vol. 1 no. 2017 (Springer, 2008).
[15]
D. Barber. Bayesian reasoning and machine learning (Cambridge University Press, 2012).
[16]
I. ISO. and B. OIML. Guide to the Expression of Uncertainty in Measurement (Aenor, 1993).
[17]
Y. Weng, Q. Li, R. Negi and M. Ilić. Semidefinite programming for power system state estimation. In: 2012 IEEE Power and Energy Society General Meeting (IEEE, 2012); pp. 1–8.
[18]
P. C. Hansen, V. Pereyra and G. Scherer. Least squares data fitting with applications (JHU Press, 2013).
[19]
G. N. Korres. A distributed multiarea state estimation. IEEE Transactions on Power Systems 26, 73–84 (2010).
[20]
M. Cosovic, M. Delalic, D. Raca and D. Vukobratovic. Observability analysis for large-scale power systems using factor graphs. IEEE Transactions on Power Systems 36, 4791–4799 (2021).
[21]
H. Horisberger. Observability analysis for power systems with measurement deficiencies. IFAC Proceedings Volumes 18, 51–58 (1985).
[22]
N. M. Manousakis and G. N. Korres. Observability analysis for power systems including conventional and phasor measurements. IET Conference Proceedings, 158-158(1) (2010).
[23]
B. Gou. Optimal placement of PMUs by integer linear programming. IEEE Transactions on power systems 23, 1525–1526 (2008).
[24]
B. Xu and A. Abur. Observability analysis and measurement placement for systems with PMUs. In: IEEE PES Power Systems Conference and Exposition, 2004. (IEEE, 2004); pp. 943–946.
+Bibliography · JuliaGrid

Bibliography

[1]
A. Gomez-Exposito, A. Abur, P. Rousseaux, A. de la Villa Jaen and C. Gomez-Quiles. On the use of PMUs in power system state estimation. In: 17th power system computation conference (2011).
[2]
G. N. Korres. Observability analysis based on Echelon form of a reduced dimensional Jacobian matrix. IEEE Transactions on Power Systems 26, 2572–2573 (2011).
[3]
M. Zhou, V. A. Centeno, J. S. Thorp and A. G. Phadke. An alternative for including phasor measurements in state estimators. IEEE transactions on power systems 21, 1930–1937 (2006).
[4]
G. Korres and N. Manousakis. State estimation and observability analysis for phasor measurement unit measured systems. IET generation, transmission & distribution 6, 902–913 (2012).
[5]
A. Abur and A. G. Exposito. Power system state estimation: theory and implementation (CRC press, 2004).
[6]
G. Andersson. Power system analysis. EEH-Power Systems Laboratory, ETH Zurich, Lecture Notes, 227–0526 (2012).
[7]
J. J. Grainger and W. D. Stevenson. Power system analysis (McGraw-Hill, 1994).
[8]
R. D. Zimmerman and C. E. Murillo-Sánchez. Matpower 6.0 users manual. Power Systems Engineering Research Center 9 (2016).
[9]
A. J. Wood, B. F. Wollenberg and G. B. Sheblé. Power generation, operation, and control (John Wiley & Sons, 2013).
[10]
R. A. Van Amerongen. A general-purpose version of the fast decoupled load flow. IEEE Transactions on Power Systems 4, 760–770 (1989).
[11]
D. P. Chassin, P. R. Armstrong, D. G. Chavarrı́a-Miranda and R. T. Guttromson. Gauss-Seidel accelerated: implementing flow solvers on field programmable gate arrays. In: 2006 IEEE Power Engineering Society General Meeting (IEEE, 2006); p. 5–pp.
[12]
F. C. Schweppe and D. B. Rom. Power system static-state estimation, Part II: Approximate model. IEEE Transactions on Power Apparatus and Systems, 125–130 (1970).
[13]
A. Monticelli. State estimation in electric power systems: a generalized approach (Springer Science & Business Media, 2012).
[14]
A. G. Phadke and J. S. Thorp. Synchronized phasor measurements and their applications. Vol. 1 no. 2017 (Springer, 2008).
[15]
D. Barber. Bayesian reasoning and machine learning (Cambridge University Press, 2012).
[16]
I. ISO. and B. OIML. Guide to the Expression of Uncertainty in Measurement (Aenor, 1993).
[17]
Y. Weng, Q. Li, R. Negi and M. Ilić. Semidefinite programming for power system state estimation. In: 2012 IEEE Power and Energy Society General Meeting (IEEE, 2012); pp. 1–8.
[18]
P. C. Hansen, V. Pereyra and G. Scherer. Least squares data fitting with applications (JHU Press, 2013).
[19]
G. N. Korres. A distributed multiarea state estimation. IEEE Transactions on Power Systems 26, 73–84 (2010).
[20]
M. Cosovic, M. Delalic, D. Raca and D. Vukobratovic. Observability analysis for large-scale power systems using factor graphs. IEEE Transactions on Power Systems 36, 4791–4799 (2021).
[21]
H. Horisberger. Observability analysis for power systems with measurement deficiencies. IFAC Proceedings Volumes 18, 51–58 (1985).
[22]
N. M. Manousakis and G. N. Korres. Observability analysis for power systems including conventional and phasor measurements. IET Conference Proceedings, 158-158(1) (2010).
[23]
B. Gou. Optimal placement of PMUs by integer linear programming. IEEE Transactions on power systems 23, 1525–1526 (2008).
[24]
B. Xu and A. Abur. Observability analysis and measurement placement for systems with PMUs. In: IEEE PES Power Systems Conference and Exposition, 2004. (IEEE, 2004); pp. 943–946.
diff --git a/dev/background/installation/index.html b/dev/background/installation/index.html index 7167ff86..160c2381 100644 --- a/dev/background/installation/index.html +++ b/dev/background/installation/index.html @@ -1,4 +1,4 @@ Installation Guide · JuliaGrid

Installation Guide

JuliaGrid is compatible with Julia version 1.9 and later. To get started with JuliaGrid, users should first install Julia and consider using a code editor for a smoother coding experience.


Install Julia

Begin by downloading and installing Julia. We can choose either the Current Stable Release or the Long-term Support Release.

The Current Stable Release is the most recent version of Julia, providing access to the latest features and typically offering better performance. For most users, we recommend installing the Current Stable Release. The Long-term Support Release is an older version of Julia that has continued to receive bug and security fixes. However, it may not have the latest features or performance improvements.


Install Code Editor

For a smoother development experience, we recommend using a code editor. While you can write Julia code in any text editor, using an integrated development environment (IDE) makes coding easier and more efficient. We suggest installing Visual Studio Code, which provides excellent support for Julia through its dedicated Julia extension. Visual Studio Code offers features like syntax highlighting, debugging, and autocompletion, making it an ideal choice for both beginners and experienced users.

The Julia extension for Visual Studio Code includes built-in dynamic autocompletion, inline results, plot pane, integrated REPL, variable view, code navigation, and many other advanced language features. For a step-by-step guide on how to use Julia in Visual Studio Code, you can follow the tutorial available here.


Install JuliaGrid

To get the JuliaGrid package installed, execute the following Julia command:

import Pkg
 Pkg.add("JuliaGrid")

When a new version of JuliaGrid is released, you can update it with the following command:

import Pkg
-Pkg.update("JuliaGrid")
+Pkg.update("JuliaGrid") diff --git a/dev/index.html b/dev/index.html index 4b30eeb4..0274dfbb 100644 --- a/dev/index.html +++ b/dev/index.html @@ -88,4 +88,4 @@ solve!(system, analysis) # Compute estimate of voltage angles residualTest!(system, device, analysis) # Perform bad data analysis and remove outlier -solve!(system, analysis) # Recompute voltage angles with the updated model

Contributors

+solve!(system, analysis) # Recompute voltage angles with the updated model

Contributors

diff --git a/dev/manual/acOptimalPowerFlow/index.html b/dev/manual/acOptimalPowerFlow/index.html index 0d84d755..10e909b7 100644 --- a/dev/manual/acOptimalPowerFlow/index.html +++ b/dev/manual/acOptimalPowerFlow/index.html @@ -138,4 +138,4 @@ | Bus 1 | 0.9279 | 9.7403 | 0.0000 | 0.0000 | -0.0000 | 3.0784 | 0.0000 | -0.0000 | | Bus 2 | 0.9140 | 11.6474 | 10.0000 | 1.0000 | 8.5166 | -3.2853 | 3.3418 | -0.0000 | | Bus 3 | 0.9000 | 9.1610 | 5.0000 | 2.0000 | -5.0000 | -2.0000 | 0.0000 | -0.0000 | -|-------------------------------------------------------------------------------------------|
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(-9.546423295966888e-9, 0.030783736488970356)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 2")(0.1851660676852624, -0.022853372793443977)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 2")(0.033417573991519366, -0.0)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(0.01718395201242816, 0.01308966404839291)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-0.016754088348856475, -0.020752498338831162)

Active and Reactive Power at Charging Admittances

To calculate the total active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(8.482586112312036e-5, -0.008482586112312037)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.0003463091379091515, 0.000692618275818303)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(0.03317417399671275, -1.4007966369074556)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by using:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(0.023278980454995702, -0.48097100965369877)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(0.02963470110066419, 2.409879948091975)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(0.026317641912190822, -0.6227571818622949)
+|-------------------------------------------------------------------------------------------|
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(-9.546423295966888e-9, 0.030783736488970356)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 2")(0.1851660676852624, -0.022853372793443977)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 2")(0.033417573991519366, -0.0)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(0.01718395201242816, 0.01308966404839291)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-0.016754088348856475, -0.020752498338831162)

Active and Reactive Power at Charging Admittances

To calculate the total active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(8.482586112312036e-5, -0.008482586112312037)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.0003463091379091515, 0.000692618275818303)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(0.03317417399671275, -1.4007966369074556)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by using:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(0.023278980454995702, -0.48097100965369877)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(0.02963470110066419, 2.409879948091975)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(0.026317641912190822, -0.6227571818622949)
diff --git a/dev/manual/acPowerFlow/index.html b/dev/manual/acPowerFlow/index.html index 98d067ff..4580bc51 100644 --- a/dev/manual/acPowerFlow/index.html +++ b/dev/manual/acPowerFlow/index.html @@ -334,4 +334,4 @@ Bus 4: 0.0

We can observe that the angles have been calculated based on the new slack bus. JuliaGrid offers the function to adjust these angles to match the original slack bus as follows:

adjustAngle!(system, analysis; slack = "Bus 1")

After executing the above code, the updated results can be viewed:

julia> print(system.bus.label, analysis.voltage.angle)Bus 1: 0.0
 Bus 2: -0.013015872071430158
 Bus 3: -0.0028853575840858334
-Bus 4: -0.013581064245677444
+Bus 4: -0.013581064245677444 diff --git a/dev/manual/acStateEstimation/index.html b/dev/manual/acStateEstimation/index.html index e84b6747..757cc678 100644 --- a/dev/manual/acStateEstimation/index.html +++ b/dev/manual/acStateEstimation/index.html @@ -330,4 +330,4 @@ io = IOBuffer() printWattmeterData(system, device, analysis, io; style = false) -CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(2.6951392445386304, 0.3132044957940553)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 1")(2.6951392445386304, 0.3132044957940553)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 1")(0.0, -0.0020066379525219783)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(1.6491130561317449, 0.2562114962034585)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-1.5932872079562321, -0.15530958620622967)

Active and Reactive Power at Charging Admittances

To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(9.800363372293906e-5, -0.03920145348917562)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.05572979175205785, 0.13932447938014464)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(2.708785622827216, -0.11569193435017798)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(1.6661346611128287, -0.1541309681169004)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(1.6709804057015962, 2.9641707920912417)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(1.6692781636392697, -0.16599467621735334)
+CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(2.6951392445386304, 0.3132044957940553)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 1")(2.6951392445386304, 0.3132044957940553)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 1")(0.0, -0.0020066379525219783)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(1.6491130561317449, 0.2562114962034585)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-1.5932872079562321, -0.15530958620622967)

Active and Reactive Power at Charging Admittances

To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(9.800363372293906e-5, -0.03920145348917562)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.05572979175205785, 0.13932447938014464)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(2.708785622827216, -0.11569193435017798)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(1.6661346611128287, -0.1541309681169004)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(1.6709804057015962, 2.9641707920912417)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(1.6692781636392697, -0.16599467621735334)
diff --git a/dev/manual/dcOptimalPowerFlow/index.html b/dev/manual/dcOptimalPowerFlow/index.html index 47300d1a..0ed6398e 100644 --- a/dev/manual/dcOptimalPowerFlow/index.html +++ b/dev/manual/dcOptimalPowerFlow/index.html @@ -140,4 +140,4 @@ | Bus 1 | 9.7403 | 0.0000 | 0.0000 | 0.0000 | | Bus 2 | 9.7405 | 0.1900 | 0.1000 | 0.0900 | | Bus 3 | 9.7402 | 0.0000 | 0.0500 | -0.0500 | -|---------------------------------------------------------------------|
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 2")0.0008999999999991246

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 2")0.0018999999999991246

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 2")7.142857142983239e-5
julia> active = toPower(system, analysis; label = "Branch 2")-7.142857142983239e-5
+|---------------------------------------------------------------------|
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 2")0.0008999999999991246

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 2")0.0018999999999991246

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 2")7.142857142983239e-5
julia> active = toPower(system, analysis; label = "Branch 2")-7.142857142983239e-5
diff --git a/dev/manual/dcPowerFlow/index.html b/dev/manual/dcPowerFlow/index.html index 55a2b8df..aad4ec60 100644 --- a/dev/manual/dcPowerFlow/index.html +++ b/dev/manual/dcPowerFlow/index.html @@ -127,4 +127,4 @@ | Branch 1 | Bus 1 | Bus 2 | 3.5714 | -3.5714 | 1 | | Branch 2 | Bus 1 | Bus 3 | 11.4286 | -11.4286 | 1 | | Branch 3 | Bus 2 | Bus 3 | -6.4286 | 6.4286 | 1 | -|-----------------------------------------------------------------------|
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 1")0.15000000000000002

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 1")0.15000000000000002

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 2")0.1142857142857143
julia> active = toPower(system, analysis; label = "Branch 2")-0.1142857142857143

Generator Active Power Output

Finally, we can compute the active power output of a particular generator using the function:

julia> active = generatorPower(system, analysis; label = "Generator 1")0.15000000000000002
+|-----------------------------------------------------------------------|
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 1")0.15000000000000002

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 1")0.15000000000000002

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 2")0.1142857142857143
julia> active = toPower(system, analysis; label = "Branch 2")-0.1142857142857143

Generator Active Power Output

Finally, we can compute the active power output of a particular generator using the function:

julia> active = generatorPower(system, analysis; label = "Generator 1")0.15000000000000002
diff --git a/dev/manual/dcStateEstimation/index.html b/dev/manual/dcStateEstimation/index.html index 7c179826..14df4b00 100644 --- a/dev/manual/dcStateEstimation/index.html +++ b/dev/manual/dcStateEstimation/index.html @@ -139,4 +139,4 @@ io = IOBuffer() printWattmeterData(system, device, analysis, io; style = false) -CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 1")0.6008333333333332

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 1")0.6008333333333332

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 1")0.17991666666666667
julia> active = toPower(system, analysis; label = "Branch 1")-0.17991666666666667
+CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active Power Injection

To calculate active power injection associated with a specific bus, the function can be used:

julia> active = injectionPower(system, analysis; label = "Bus 1")0.6008333333333332

Active Power Injection from Generators

To calculate active power injection from the generators at a specific bus, the function can be used:

julia> active = supplyPower(system, analysis; label = "Bus 1")0.6008333333333332

Active Power Flow

Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active = fromPower(system, analysis; label = "Branch 1")0.17991666666666667
julia> active = toPower(system, analysis; label = "Branch 1")-0.17991666666666667
diff --git a/dev/manual/measurementModel/index.html b/dev/manual/measurementModel/index.html index bf702e3c..8f56baf4 100644 --- a/dev/manual/measurementModel/index.html +++ b/dev/manual/measurementModel/index.html @@ -9,7 +9,7 @@ addVoltmeter!(system, device; bus = "Bus 1", magnitude = 1.0, variance = 1e-3) addWattmeter!(system, device; from = "Branch 1", active = 0.2, variance = 1e-4, noise = true)

In this context, we have created the voltmeter responsible for measuring the bus voltage magnitude at Bus 1, with associated mean and variance values expressed in per-units:

julia> [device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]1×2 Matrix{Float64}:
  1.0  0.001

Furthermore, we have established the wattmeter to measure the active power flow at the from-bus end of Branch 1, with corresponding mean and variance values also expressed in per-units:

julia> [device.wattmeter.active.mean device.wattmeter.active.variance]1×2 Matrix{Float64}:
- 0.201216  0.0001
Tip

The measurement values (i.e., means) can be generated by adding white Gaussian noise with specified variance values to perturb the original values. This can be achieved by setting noise = true within the functions used for adding devices.


Save Model

Once the Measurement type has been created using one of the methods outlined in Build Model, the current data can be stored in the HDF5 file by using saveMeasurement function:

saveMeasurement(device; path = "C:/hdf5/measurement.h5")

All electrical quantities saved in the HDF5 file are in per-units and radians.


Add Voltmeter

We have the option to add voltmeters to a loaded measurement type or to one created from scratch. As an example, we can initiate the Measurement type and then incorporate voltmeters by utilizing the addVoltmeter! function:

system = powerSystem()
+ 0.207552  0.0001
Tip

The measurement values (i.e., means) can be generated by adding white Gaussian noise with specified variance values to perturb the original values. This can be achieved by setting noise = true within the functions used for adding devices.


Save Model

Once the Measurement type has been created using one of the methods outlined in Build Model, the current data can be stored in the HDF5 file by using saveMeasurement function:

saveMeasurement(device; path = "C:/hdf5/measurement.h5")

All electrical quantities saved in the HDF5 file are in per-units and radians.


Add Voltmeter

We have the option to add voltmeters to a loaded measurement type or to one created from scratch. As an example, we can initiate the Measurement type and then incorporate voltmeters by utilizing the addVoltmeter! function:

system = powerSystem()
 device = measurement()
 
 addBus!(system; label = "Bus 1")
@@ -17,7 +17,7 @@
 addVoltmeter!(system, device; bus = "Bus 1", magnitude = 0.9, variance = 1e-4)
 addVoltmeter!(system, device; bus = "Bus 1", magnitude = 1.0, variance = 1e-3, noise = true)

In this example, we have established two voltmeters designed to measure the bus voltage magnitude at Bus 1. In the case of the second voltmeter, the measurement value is generated internally by introducing white Gaussian noise with the variance added to the magnitude value. As a result, we obtain the following data:

julia> [device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]2×2 Matrix{Float64}:
  0.9       0.0001
- 0.987789  0.001
Info

We recommend reading the documentation for the addVoltmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the magnitude and variance keywords are expected to be provided in per-units (pu). However, users have the flexibility to specify these values in volts (V) if they prefer. For instance, consider the following example:

@voltage(kV, rad, V)
+ 0.966116  0.001
Info

We recommend reading the documentation for the addVoltmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the magnitude and variance keywords are expected to be provided in per-units (pu). However, users have the flexibility to specify these values in volts (V) if they prefer. For instance, consider the following example:

@voltage(kV, rad, V)
 
 system = powerSystem()
 device = measurement()
@@ -27,7 +27,7 @@
 addVoltmeter!(system, device; bus = "Bus 1", magnitude = 121.5, variance = 0.0135)
 addVoltmeter!(system, device; bus = "Bus 1", magnitude = 135, variance = 0.135, noise = true)

In this example, we have chosen to specify magnitude and variance in kilovolts (kV). It is important to note that even though we have used kilovolts as the input units, these keywords will still be stored in the per-units:

julia> [device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]2×2 Matrix{Float64}:
  0.9       0.0001
- 0.959694  0.001
Info

When users choose to input data in volts, measurement values and variances are related to line-to-neutral voltages, while the base values are defined for line-to-line voltages. Therefore, a conversion using $\sqrt{3}$ is necessary. For more information, refer to the Per-Unit System section.


Users have the option to print the voltmeter data in the REPL using any units that have been configured:

printVoltmeterData(system, device)
|-----------------------------------------|
+ 0.976064  0.001
Info

When users choose to input data in volts, measurement values and variances are related to line-to-neutral voltages, while the base values are defined for line-to-line voltages. Therefore, a conversion using $\sqrt{3}$ is necessary. For more information, refer to the Per-Unit System section.


Users have the option to print the voltmeter data in the REPL using any units that have been configured:

printVoltmeterData(system, device)
|-----------------------------------------|
 | Voltmeter Data                          |
 |-----------------------------------------|
 | Label |        Voltage Magnitude        |
@@ -36,7 +36,7 @@
 |       |        [kV] |     [kV] |        |
 |-------|-------------|----------|--------|
 | 1     |    121.5000 | 1.35e-02 |      1 |
-| 2     |    129.5587 | 1.35e-01 |      1 |
+| 2     |    131.7686 | 1.35e-01 |      1 |
 |-----------------------------------------|

Add Ammeter

Users can introduce ammeters into either an existing measurement type or one that they create from the ground up by making use of the addAmmeter! function, as demonstrated in the following example:

system = powerSystem()
 device = measurement()
 
@@ -46,8 +46,8 @@
 
 addAmmeter!(system, device; from = "Branch 1", magnitude = 0.8, variance = 1e-3)
 addAmmeter!(system, device; to = "Branch 1", magnitude = 0.9, variance = 1e-1, noise = true)

In this scenario, we have established one ammeter to measure the branch current magnitude at the from-bus end of Branch 1, as indicated by the use of the from keyword. Similarly, we have added an ammeter to measure the branch current magnitude at the to-bus end of the branch by utilizing the to keyword.

For the first ammeter, we assume that the measurement value is already known, defined by the magnitude. In contrast, for the second ammeter, the measurement value is generated by adding white Gaussian noise with the variance to the magnitude value. These actions result in the following outcomes:

julia> [device.ammeter.magnitude.mean device.ammeter.magnitude.variance]2×2 Matrix{Float64}:
- 0.8       0.001
- 0.874787  0.1
Info

We recommend reading the documentation for the addAmmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the magnitude and variance keywords are expected to be provided in per-unit (pu). However, users have the flexibility to express these values in amperes (A) if they prefer. Take a look at the following example:

@current(A, rad)
+ 0.8      0.001
+ 1.37706  0.1
Info

We recommend reading the documentation for the addAmmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the magnitude and variance keywords are expected to be provided in per-unit (pu). However, users have the flexibility to express these values in amperes (A) if they prefer. Take a look at the following example:

@current(A, rad)
 
 system = powerSystem()
 device = measurement()
@@ -59,7 +59,7 @@
 addAmmeter!(system, device; from = "Branch 1", magnitude = 342.13, variance = 0.428)
 addAmmeter!(system, device; to = "Branch 1", magnitude = 385, variance = 42.8, noise = true)

In this example, we have opted to specify the magnitude and variance in amperes (A). It is worth noting that, despite using amperes as the input units, these keywords will still be stored in the per-unit system:

julia> [device.ammeter.magnitude.mean device.ammeter.magnitude.variance]2×2 Matrix{Float64}:
  0.799992  0.00100078
- 0.827342  0.100078

Users have the option to print the ammeter data in the REPL using any units that have been configured:

printAmmeterData(system, device)
|-----------------------------------------|
+ 1.05377   0.100078

Users have the option to print the ammeter data in the REPL using any units that have been configured:

printAmmeterData(system, device)
|-----------------------------------------|
 | Ammeter Data                            |
 |-----------------------------------------|
 | Label |        Current Magnitude        |
@@ -68,7 +68,7 @@
 |       |         [A] |      [A] |        |
 |-------|-------------|----------|--------|
 | 1     |    342.1300 | 4.28e-01 |      1 |
-| 2     |    353.8268 | 4.28e+01 |      1 |
+| 2     |    450.6612 | 4.28e+01 |      1 |
 |-----------------------------------------|

Add Wattmeter

Users can include wattmeters in either an existing measurement type or one that they create from scratch by utilizing the addWattmeter! function, as demonstrated in the following example:

system = powerSystem()
 device = measurement()
 
@@ -81,7 +81,7 @@
 addWattmeter!(system, device; to = "Branch 1", active = 0.1, variance = 1e-3, noise = true)

In this scenario, one wattmeter has been added to measure the active power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two wattmeters have been introduced to measure the active power flow on both sides of Branch 1 using the from and to keywords.

For the first and second wattmeters, we assume that the measurement values are already known, defined by the active. In contrast, for the third wattmeter, the measurement value is generated by adding white Gaussian noise with the variance to the active value. As a result, the measurement data is as follows:

julia> [device.wattmeter.active.mean device.wattmeter.active.variance]3×2 Matrix{Float64}:
  0.6       0.001
  0.3       0.01
- 0.118478  0.001
Info

We recommend reading the documentation for the addWattmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the active and variance keywords are expected to be provided in per-unit (pu) values. However, users have the option to express these values in watts (W) if they prefer, as demonstrated in the following example:

@power(MW, pu, pu)
+ 0.101661  0.001
Info

We recommend reading the documentation for the addWattmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

By default, the active and variance keywords are expected to be provided in per-unit (pu) values. However, users have the option to express these values in watts (W) if they prefer, as demonstrated in the following example:

@power(MW, pu, pu)
 
 system = powerSystem()
 device = measurement()
@@ -93,9 +93,9 @@
 addWattmeter!(system, device; bus = "Bus 1", active = 60, variance = 1e-1)
 addWattmeter!(system, device; from = "Branch 1", active = 30, variance = 1)
 addWattmeter!(system, device; to = "Branch 1", active = 10, variance = 1e-1, noise = true)

In this example, we have chosen to specify the active and variance in megawatts (MW), but even though we have used megawatts as the input units, these keywords will still be stored in the per-unit system:

julia> [device.wattmeter.active.mean device.wattmeter.active.variance]3×2 Matrix{Float64}:
- 0.6       0.001
- 0.3       0.01
- 0.167403  0.001

Users have the option to print the wattmeter data in the REPL using any units that have been configured:

printWattmeterData(system, device)
|-----------------------------------------|
+ 0.6        0.001
+ 0.3        0.01
+ 0.0945196  0.001

Users have the option to print the wattmeter data in the REPL using any units that have been configured:

printWattmeterData(system, device)
|-----------------------------------------|
 | Wattmeter Data                          |
 |-----------------------------------------|
 | Label |          Active Power           |
@@ -105,7 +105,7 @@
 |-------|-------------|----------|--------|
 | 1     |     60.0000 | 1.00e-01 |      1 |
 | 2     |     30.0000 | 1.00e+00 |      1 |
-| 3     |     16.7403 | 1.00e-01 |      1 |
+| 3     |      9.4520 | 1.00e-01 |      1 |
 |-----------------------------------------|

Add Varmeter

To include varmeters, the same approach as described in the Add Wattmeter section can be applied, but here, we make use of the addVarmeter! function, as demonstrated in the following example:

system = powerSystem()
 device = measurement()
 
@@ -116,9 +116,9 @@
 addVarmeter!(system, device; bus = "Bus 1", reactive = 0.2, variance = 1e-3)
 addVarmeter!(system, device; from = "Branch 1", reactive = 0.1, variance = 1e-2)
 addVarmeter!(system, device; to = "Branch 1", reactive = 0.05, variance = 1e-3, noise = true)

In this context, one varmeter has been added to measure the reactive power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two varmeters have been introduced to measure the reactive power flow on both sides of Branch 1 using the from and to keywords. As a result, the following outcomes are observed:

julia> [device.varmeter.reactive.mean device.varmeter.reactive.variance]3×2 Matrix{Float64}:
- 0.2       0.001
- 0.1       0.01
- 0.135928  0.001
Info

We recommend reading the documentation for the addVarmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

Just as we explained for the previous device, users have the flexibility to select units different from per-units. In this case, they can opt for megavolt-ampere reactive (MVAr), as illustrated in the following example:

@power(pu, MVAr, pu)
+ 0.2        0.001
+ 0.1        0.01
+ 0.0156867  0.001
Info

We recommend reading the documentation for the addVarmeter! function, where we have provided a list of the keywords that can be used.


Customizing Input Units for Keywords

Just as we explained for the previous device, users have the flexibility to select units different from per-units. In this case, they can opt for megavolt-ampere reactive (MVAr), as illustrated in the following example:

@power(pu, MVAr, pu)
 
 system = powerSystem()
 device = measurement()
@@ -132,7 +132,7 @@
 addVarmeter!(system, device; to = "Branch 1", reactive = 5, variance = 1e-1, noise = true)

JuliaGrid will still store the values in the per-unit system:

julia> [device.varmeter.reactive.mean device.varmeter.reactive.variance]3×2 Matrix{Float64}:
  0.2        0.001
  0.1        0.01
- 0.0475853  0.001

Users have the option to print the varmeter data in the REPL using any units that have been configured:

printVarmeterData(system, device)
|-----------------------------------------|
+ 0.0370548  0.001

Users have the option to print the varmeter data in the REPL using any units that have been configured:

printVarmeterData(system, device)
|-----------------------------------------|
 | Varmeter Data                           |
 |-----------------------------------------|
 | Label |         Reactive Power          |
@@ -142,7 +142,7 @@
 |-------|-------------|----------|--------|
 | 1     |     20.0000 | 1.00e-01 |      1 |
 | 2     |     10.0000 | 1.00e+00 |      1 |
-| 3     |      4.7585 | 1.00e-01 |      1 |
+| 3     |      3.7055 | 1.00e-01 |      1 |
 |-----------------------------------------|

Add PMU

Users have the capability to incorporate PMUs into either an existing measurement type or create one from scratch by utilizing the addPmu! function, as demonstrated in the following example:

system = powerSystem()
 device = measurement()
 
@@ -154,10 +154,10 @@
 addPmu!(system, device; from = "Branch 1", magnitude = 1.0, angle = -0.2, noise = true)
 addPmu!(system, device; to = "Branch 1", magnitude = 0.9, angle = 0.0, varianceAngle = 0.001)
Info

While the typical understanding of a PMU encompasses a device that measures the bus voltage phasor and all branch current phasors incident to the bus, we have chosen to deconstruct this concept to offer users increased flexibility. As a result, our approach yields PMUs that measure individual phasors, each described with magnitude and angle, along with corresponding variances, all presented in the polar coordinate system.

In this context, one PMU has been added to measure the bus voltage phasor at Bus 1, as indicated by the use of the bus keyword. Additionally, two PMUs have been introduced to measure the branch current phasors on both sides of Branch 1 using the from and to keywords.

For the first and third PMUs, we assume that the measurement values are already known, defined by the magnitude and angle keywords. However, for the second PMU, we generate the measurement value by adding white Gaussian noise with varianceMagnitude and varianceAngle to the magnitude and angle values, respectively. It is important to note that when we omit specifying variance values, we rely on their default settings, both of which are equal to 1e-5. As a result, we observe the following outcomes:

julia> [device.pmu.magnitude.mean device.pmu.magnitude.variance]3×2 Matrix{Float64}:
  1.1       0.1
- 0.999737  1.0e-5
+ 0.994494  1.0e-5
  0.9       1.0e-5
julia> [device.pmu.angle.mean device.pmu.angle.variance]3×2 Matrix{Float64}: 0.1 1.0e-5 - -0.198485 1.0e-5 + -0.197758 1.0e-5 0.0 0.001
Info

We recommend reading the documentation for the addPmu! function, where we have provided a list of the keywords that can be used.


Coordinate Systems and Correlated Measurement Errors

When users add PMUs, the incorporation of these measurements into the state estimation model is always in the rectangular coordinate system. In this scenario, the real and imaginary components of the phasor measurements become correlated, although typically these correlations are disregarded [1]. However, if users want to consider these error correlations, the keyword correlated = true is provided for support.

Further, in the AC state estimation model, users have the flexibility to integrate PMU outputs in the polar coordinate system by specifying polar = true.

For example, let us add PMUs:

addPmu!(system, device; bus = "Bus 2", magnitude = 0.9, angle = 0, correlated = true)
 addPmu!(system, device; bus = "Bus 2", magnitude = 0.9, angle = 0, polar = true)

In the case of linear state estimation using PMUs only, both PMUs will be integrated into the rectangular coordinate system because the polar keyword is only related to AC state estimation. The treatment of the first PMU assumes error correlation between the real and imaginary parts. Conversely, the treatment of the second PMU assumes no correlation, as it defaults to correlated = false.

Next, in AC state estimation, the first PMU measurement will be integrated into the rectangular coordinate system where correlation between the real and imaginary parts exists. The second PMU will be integrated in the polar coordinate system.

Tip

It is noteworthy that expressing current phasor measurements in polar coordinates can lead to ill-conditioned problems due to small current magnitudes, whereas using rectangular representation can resolve this issue.


Customizing Input Units for Keywords

By default, the magnitude and varianceMagnitude keywords are expected to be provided in per-unit (pu), while the angle and varianceAngle keywords are expected to be provided in radians (rad). However, users have the flexibility to express these values in different units, such as volts (V) and degrees (deg) if the PMU is set to a bus, or amperes (A) and degrees (deg) if the PMU is set to a branch. This flexibility is demonstrated in the following:

@voltage(kV, deg, V)
 @current(A, deg)
@@ -170,13 +170,13 @@
 addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.12)
 
 addPmu!(system, device; bus = "Bus 1", magnitude = 85.74, angle = 5.73, varianceAngle = 0.06)
-addPmu!(system, device; from = "Branch 1", magnitude = 167.35, angle = -11.46, noise = true)
-addPmu!(system, device; to = "Branch 1", magnitude = 150.61, angle = 0.0)

In this example, we have opted to specify kilovolts (kV) and degrees (deg) for the PMU located at Bus 1, and amperes (A) and degrees (deg) for the PMUs located at Branch 1. It is important to note that regardless of the units used, the values will still be stored in per-units and radians:

julia> [device.pmu.magnitude.mean device.pmu.magnitude.variance]3×2 Matrix{Float64}:
+addPmu!(system, device; from = "Branch 1", magnitude = 427.67, angle = -11.46, noise = true)
+addPmu!(system, device; to = "Branch 1", magnitude = 384.91, angle = 0.0)

In this example, we have opted to specify kilovolts (kV) and degrees (deg) for the PMU located at Bus 1, and amperes (A) and degrees (deg) for the PMUs located at Branch 1. It is important to note that regardless of the units used, the values will still be stored in per-units and radians:

julia> [device.pmu.magnitude.mean device.pmu.magnitude.variance]3×2 Matrix{Float64}:
  1.10004   1.0e-5
- 0.392751  1.0e-5
- 0.352167  1.0e-5
julia> [device.pmu.angle.mean device.pmu.angle.variance]3×2 Matrix{Float64}: + 0.995383 1.0e-5 + 0.900023 1.0e-5
julia> [device.pmu.angle.mean device.pmu.angle.variance]3×2 Matrix{Float64}: 0.100007 0.0010472 - -0.196801 1.0e-5 + -0.195113 1.0e-5 0.0 1.0e-5

Users have the option to print the PMU data in the REPL using any units that have been configured:

printPmuData(system, device)
|---------------------------------------------------------------------------|
 | PMU Data                                                                  |
 |---------------------------------------------------------------------------|
@@ -195,8 +195,8 @@
 |       | Measurement | Variance | Status | Measurement | Variance | Status |
 |       |         [A] |      [A] |        |       [deg] |    [deg] |        |
 |-------|-------------|----------|--------|-------------|----------|--------|
-| 2     |    167.9665 | 4.28e-03 |      1 |    -11.2758 | 5.73e-04 |      1 |
-| 3     |    150.6100 | 4.28e-03 |      1 |      0.0000 | 5.73e-04 |      1 |
+| 2     |    425.6923 | 4.28e-03 |      1 |    -11.1792 | 5.73e-04 |      1 |
+| 3     |    384.9100 | 4.28e-03 |      1 |      0.0000 | 5.73e-04 |      1 |
 |---------------------------------------------------------------------------|

Add Templates

The functions addVoltmeter!, addAmmeter!, addWattmeter!, addVarmeter!, and addPmu! are employed to introduce measurement devices. In cases where specific keywords are not explicitly defined, default values are automatically assigned to certain parameters.


Default Keyword Values

When utilizing the addVoltmeter! function, the default variance is set to variance = 1e-2 per-unit, and the voltmeter's operational status is automatically assumed to be in-service, as indicated by the setting of status = 1.

Similarly, for the addAmmeter! function, the default variances are established at variance = 1e-2 per-unit, and the operational statuses are configured to status = 1. This means that if a user places an ammeter at either the from-bus or to-bus end of a branch, the default settings are identical. However, as we will explain in the following subsection, users have the flexibility to fine-tune these default values, differentiating between the two locations.

In alignment with ammeters, the addWattmeter! and addVarmeter! functions feature default variances set at variance = 1e-2 per-unit, and statuses are automatically assigned as status = 1, regardless of whether the wattmeter or varmeter is placed at the bus, the from-bus end, or the to-bus end. Users have the ability to customize these default values, making distinctions between the three positions of the measurement devices.

For the addPmu! function, variances for both magnitude and angle measurements are standardized to varianceMagnitude = 1e-5 and varianceAngle = 1e-5 in per-units. Likewise, operational statuses are uniformly set to statusMagnitude = 1 and statusAngle = 1, regardless of whether the PMU is positioned on the bus, the from-bus end, or the to-bus end. Once more, users retain the option to tailor these default values to their specific needs, allowing for distinctions between these three locations of the measurement devices. Additionally, the coordinate system utilized for AC state estimation is consistently configured with polar = false, while correlation in the rectangular system is disabled with correlated = false.

Across all measurement devices, the method for generating measurement means is established as noise = false.


Change Default Keyword Values

In JuliaGrid, users have the flexibility to customize default values and assign personalized settings using the @voltmeter, @ammeter, @wattmeter, @varmeter, and @pmu macros. These macros create voltmeter, ammeter, wattmeter, varmeter, and pmu templates that are employed each time functions for adding measurement devices are called. Here is an example of creating these templates with tailored default values:

system = powerSystem()
 device = measurement()
 
@@ -380,4 +380,4 @@
 
 addVoltmeter!(system, device, analysis)
 addAmmeter!(system, device, analysis)
-addPmu!(system, device, analysis)

Activating Devices

As a starting point, we create the measurement set where all devices are set to in-service mode based on default settings. In this instance, we generate the measurement set comprising 3 voltmeters, 6 ammeters, and 9 PMUs.

Subsequently, we offer users the ability to manipulate the status of in-service devices using the status! function. For example, within this set, if we wish to have only 12 out of the total 18 devices in-service while the rest are out-of-service, we can accomplish this as follows:

status!(system, device; inservice = 12)

Upon executing this function, 12 devices will be randomly selected to be in-service, while the remaining 6 will be set to out-of-service.

Furthermore, users can fine-tune the manipulation of specific measurements. Let us say we want to activate only 2 ammeters while deactivating the remaining ammeters:

statusAmmeter!(system, device; inservice = 2)

This action will result in 2 ammeters being in-service and 4 being out-of-service.

Users also have the option to further refine these actions by specifying devices at particular locations within the power system. For instance, we can enable 3 PMUs at buses to measure bus voltage phasors while deactivating all PMUs at branches that measure current phasors:

statusPmu!(system, device; inserviceBus = 3, inserviceFrom = 0, inserviceTo = 0)

The outcome will be that 3 PMUs are set to in-service at buses for voltage phasor measurements, while all PMUs at branches measuring current phasors will be in out-of-service mode.


Deactivating Devices

Likewise, we empower users to specify the number of devices to be set as out-of-service rather than defining the number of in-service devices. For instance, if the intention is to deactivate just 2 devices from the total measurement set, it can be achieved as follows:

status!(system, device; outservice = 2)

In this scenario 2 devices will be randomly deactivated, while the rest will remain in in-service status. Similar to the previous approach, users can apply this to specific devices or employ fine-tuning as needed.


Activating Devices Using Redundancy

Furthermore, users can take advantage of redundancy, which represents the ratio between measurement devices and state variables. For example, if we wish to have the number of measurement devices be 1.2 times greater than the number of state variables, we can utilize the following command:

status!(system, device; redundancy = 1.2)

Considering that the number of state variables is 5 (excluding the voltage angle related to the slack bus), using a redundancy value of 1.2 will result in 6 devices being set to in-service, while the remainder will be deactivated. As before, users can target specific devices or adjust settings as needed.

+addPmu!(system, device, analysis)
Activating Devices

As a starting point, we create the measurement set where all devices are set to in-service mode based on default settings. In this instance, we generate the measurement set comprising 3 voltmeters, 6 ammeters, and 9 PMUs.

Subsequently, we offer users the ability to manipulate the status of in-service devices using the status! function. For example, within this set, if we wish to have only 12 out of the total 18 devices in-service while the rest are out-of-service, we can accomplish this as follows:

status!(system, device; inservice = 12)

Upon executing this function, 12 devices will be randomly selected to be in-service, while the remaining 6 will be set to out-of-service.

Furthermore, users can fine-tune the manipulation of specific measurements. Let us say we want to activate only 2 ammeters while deactivating the remaining ammeters:

statusAmmeter!(system, device; inservice = 2)

This action will result in 2 ammeters being in-service and 4 being out-of-service.

Users also have the option to further refine these actions by specifying devices at particular locations within the power system. For instance, we can enable 3 PMUs at buses to measure bus voltage phasors while deactivating all PMUs at branches that measure current phasors:

statusPmu!(system, device; inserviceBus = 3, inserviceFrom = 0, inserviceTo = 0)

The outcome will be that 3 PMUs are set to in-service at buses for voltage phasor measurements, while all PMUs at branches measuring current phasors will be in out-of-service mode.


Deactivating Devices

Likewise, we empower users to specify the number of devices to be set as out-of-service rather than defining the number of in-service devices. For instance, if the intention is to deactivate just 2 devices from the total measurement set, it can be achieved as follows:

status!(system, device; outservice = 2)

In this scenario 2 devices will be randomly deactivated, while the rest will remain in in-service status. Similar to the previous approach, users can apply this to specific devices or employ fine-tuning as needed.


Activating Devices Using Redundancy

Furthermore, users can take advantage of redundancy, which represents the ratio between measurement devices and state variables. For example, if we wish to have the number of measurement devices be 1.2 times greater than the number of state variables, we can utilize the following command:

status!(system, device; redundancy = 1.2)

Considering that the number of state variables is 5 (excluding the voltage angle related to the slack bus), using a redundancy value of 1.2 will result in 6 devices being set to in-service, while the remainder will be deactivated. As before, users can target specific devices or adjust settings as needed.

diff --git a/dev/manual/pmuStateEstimation/index.html b/dev/manual/pmuStateEstimation/index.html index 03c21e2b..d33486ad 100644 --- a/dev/manual/pmuStateEstimation/index.html +++ b/dev/manual/pmuStateEstimation/index.html @@ -218,4 +218,4 @@ io = IOBuffer() printPmuData(system, device, analysis, io; style = false) -CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(2.7128789695754727, 0.43288460463326406)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 1")(2.7128789695754727, 0.43288460463326406)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 1")(0.0, -0.002000424255767445)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(1.6429108157162793, 0.255391331637058)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-1.5873301378903089, -0.1549833506018255)

Active and Reactive Power at Charging Admittances

To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(9.705560639418611e-5, -0.03882224255767445)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.05548491704701527, 0.13871229261753815)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(2.7469074926874932, -0.15817873160622747)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(1.662466361408605, -0.1541623914297243)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(1.6673093443308729, 2.964124299788863)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(1.6656067520128401, -0.1660336726001753)
+CSV.write("bus.csv", CSV.File(take!(io); delim = "|"))
Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, the function can be used:

julia> active, reactive = injectionPower(system, analysis; label = "Bus 1")(2.7128789695754727, 0.43288460463326406)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:

julia> active, reactive = supplyPower(system, analysis; label = "Bus 1")(2.7128789695754727, 0.43288460463326406)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:

julia> active, reactive = shuntPower(system, analysis; label = "Bus 1")(0.0, -0.002000424255767445)

Active and Reactive Power Flow

Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> active, reactive = fromPower(system, analysis; label = "Branch 2")(1.6429108157162793, 0.255391331637058)
julia> active, reactive = toPower(system, analysis; label = "Branch 2")(-1.5873301378903089, -0.1549833506018255)

Active and Reactive Power at Charging Admittances

To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:

julia> active, reactive = chargingPower(system, analysis; label = "Branch 1")(9.705560639418611e-5, -0.03882224255767445)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, the function can be used:

julia> active, reactive = seriesPower(system, analysis; label = "Branch 2")(0.05548491704701527, 0.13871229261753815)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, the function can be used:

julia> magnitude, angle = injectionCurrent(system, analysis; label = "Bus 1")(2.7469074926874932, -0.15817873160622747)

Current Flow

We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:

julia> magnitude, angle = fromCurrent(system, analysis; label = "Branch 2")(1.662466361408605, -0.1541623914297243)
julia> magnitude, angle = toCurrent(system, analysis; label = "Branch 2")(1.6673093443308729, 2.964124299788863)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:

julia> magnitude, angle = seriesCurrent(system, analysis; label = "Branch 2")(1.6656067520128401, -0.1660336726001753)
diff --git a/dev/manual/powerSystemModel/index.html b/dev/manual/powerSystemModel/index.html index 9197db57..55f5b22d 100644 --- a/dev/manual/powerSystemModel/index.html +++ b/dev/manual/powerSystemModel/index.html @@ -196,4 +196,4 @@ 500.0 150.0

Similarly, we can define the linear piecewise cost using megavolt-amperes reactive:

cost!(system; label = "Generator 1", reactive = 1, piecewise = [11.0 12.3; 15.0 16.8])

Upon inspection, we can see that the stored data is the same as before:

julia> system.generator.cost.reactive.piecewise[1]2×2 Matrix{Float64}:
  0.11  12.3
- 0.15  16.8
Tip

The cost! function not only adds costs but also allows users to update previously defined cost functions. This functionality is particularly valuable in optimal power flow analyses, as it allows users to modify generator power costs without the need to recreate models from scratch.

+ 0.15 16.8
Tip

The cost! function not only adds costs but also allows users to update previously defined cost functions. This functionality is particularly valuable in optimal power flow analyses, as it allows users to modify generator power costs without the need to recreate models from scratch.

diff --git a/dev/search_index.js b/dev/search_index.js index afadf4e5..c602fa64 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"#JuliaGrid","page":"Introduction","title":"JuliaGrid","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid is a fast, flexible, and easy-to-use open-source tool for analyzing and modifying power system configurations and measurement data. It represents a comprehensive framework for steady-state power system analysis written in the Julia programming language. The framework is available as a Julia package under MIT License. JuliaGrid is primarily designed for researchers and academics, providing various state-of-the-art algorithms.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The framework's architecture centres around code-reusability paradigm, allowing users a high level of customization for their experiments. To simplify, the overall logic for setting the experiments and its analysis can be as follows:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Users define a power system with/without measurement data.\nUsers select between the AC or DC model.\nUsers define the specific type of required analysis.\nFinally, they solve the generated power system model.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Installation-Guide","page":"Introduction","title":"Installation Guide","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid is compatible with Julia version 1.9 and later. To get started with JuliaGrid, users should first install Julia and consider using a code editor for a smoother coding experience. For detailed instructions, please consult the Installation Guide.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To get the JuliaGrid package installed, execute the following Julia command:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"import Pkg\nPkg.add(\"JuliaGrid\")","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Documentation-Structure","page":"Introduction","title":"Documentation Structure","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid documentation consists of three main parts:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The manual provides users with guidance on how to use available functions, its return values, and offers instructions for modifying power system configurations, measurement data, and other user specific analysis.\nThe tutorials delve deeper into the theoretical underpinnings of state-of-the-art algorithms, allowing users to gain an in-depth understanding of the equations used in various functions.\nAPI references offer a comprehensive list of objects, functions and methods within the package, categorised according to specific use-cases.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Getting-Started","page":"Introduction","title":"Getting Started","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Below, we have provided a list of exhaustive examples in order to ease users in getting started with the JuliaGrid package. These examples highlight some of the functionalities that the framework offers.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-Power-Flow","page":"Introduction","title":"AC Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = newtonRaphson(system) # Build the power flow model\nfor iteration = 1:10 # Begin the iteration loop\n stopping = mismatch!(system, analysis) # Compute power mismatches\n if all(stopping .< 1e-8) # Check if the stopping criterion is met\n println(\"Solution Found.\") # Output message indicating convergence\n break # Stop iterations if the criterion is met\n end\n solve!(system, analysis) # Compute voltage magnitudes and angles\nend\npower!(system, analysis) # Compute powers within the power system\ncurrent!(system, analysis) # Compute currents within the power system\n\nprintBusData(system, analysis) # Print data related to buses","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-Power-Flow","page":"Introduction","title":"DC Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\n@power(MW, MVAr, MVA) # Specify the power units for input data\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcPowerFlow(system) # Build the power flow analysis\nsolve!(system, analysis) # Compute voltage angles\n\n@generator(active = 20) # Define the template for generators\naddGenerator!(system, analysis; bus = 1) # Add the new generator to the power system\nsolve!(system, analysis) # Recompute voltage angles with the updated model\n\nprintBusSummary(system, analysis) # Print a summary of data related to buses","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-Optimal-Power-Flow","page":"Introduction","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid, Ipopt\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer) # Build the optimal power flow model\nsolve!(system, analysis) # Compute generator powers and bus voltages\ncurrent!(system, analysis) # Compute currents within the power system\n\n@branch(resistance = 0.01, reactance = 0.2) # Define the new template for branches\naddBranch!(system, analysis; from = 1, to = 5) # Add the new branch to the power system\nsolve!(system, analysis) # Recompute solutions with the updated model","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-Optimal-Power-Flow","page":"Introduction","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid, HiGHS\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer) # Build the optimal power flow model\nsolve!(system, analysis) # Compute generator powers and bus voltages\npower!(system, analysis) # Compute active powers within the power system\n\nprintBranchData(system, analysis) # Print data related to branches","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-State-Estimation","page":"Introduction","title":"AC State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = gaussNewton(system, device) # Build the state estimation model\nfor iteration = 1:20 # Begin the iteration loop\n stopping = solve!(system, analysis) # Compute estimate of voltages\n if stopping < 1e-8 # Check if the stopping criterion is met\n println(\"Solution Found.\") # Output message indicating convergence\n break # Stop iterations if the criterion is met\n end\nend\npower!(system, analysis) # Compute active powers within the power system\n\nprintWattmeterData(system, device, analysis) # Print data related to wattmeters","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#PMU-State-Estimation","page":"Introduction","title":"PMU State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = pmuStateEstimation(system, device) # Build the state estimation model\nsolve!(system, analysis) # Compute estimate of voltages\n\nupdatePmu!(system, device, analysis; label = \"To 1\", angle = 0.0) # Update phasor measurement\nsolve!(system, analysis) # Recompute the solution with the updated model\n\nprintPmuData(system, device, analysis) # Print data related to PMUs","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-State-Estimation","page":"Introduction","title":"DC State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcStateEstimation(system, device) # Build the state estimation model\nsolve!(system, analysis) # Compute estimate of voltage angles\n\nresidualTest!(system, device, analysis) # Perform bad data analysis and remove outlier\nsolve!(system, analysis) # Recompute voltage angles with the updated model","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Contributors","page":"Introduction","title":"Contributors","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Ognjen Kundacina - The Institute for Artificial Intelligence Research and Development of Serbia\nMuhamed Delalic - University of Sarajevo, Bosnia and Herzegovina\nArmin Teskeredzic - RWTH Aachen University, Germany\nMirsad Cosovic - University of Sarajevo, Bosnia and Herzegovina","category":"page"},{"location":"api/optimalPowerFlow/#OptimalPowerFlowAPI","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"For further information on this topic, please see the AC Optimal Power Flow or DC Optimal Power Flow sections of the Manual. Below, we have provided a list of functions that can be utilized for optimal power flow analysis.","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"To load optimal power flow API functionalities into the current scope, one can employ the following command:","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"using JuliaGrid, Ipopt, HiGHS","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#AC-Optimal-Power-Flow","page":"Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"acOptimalPowerFlow\nsolve!\nstartingPrimal!\nstartingDual!","category":"page"},{"location":"api/optimalPowerFlow/#DC-Optimal-Power-Flow","page":"Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"dcOptimalPowerFlow\nsolve!\nstartingPrimal!\nstartingDual!","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#AC-Optimal-Power-Flow-2","page":"Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"acOptimalPowerFlow\nsolve!(::PowerSystem, ::ACOptimalPowerFlow)\nstartingPrimal!(::PowerSystem, ::ACOptimalPowerFlow)\nstartingDual!(::PowerSystem, ::ACOptimalPowerFlow)","category":"page"},{"location":"api/optimalPowerFlow/#JuliaGrid.acOptimalPowerFlow","page":"Optimal Power Flow","title":"JuliaGrid.acOptimalPowerFlow","text":"acOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name,\n magnitude, angle, active, reactive)\n\nThe function sets up the optimization model for solving the AC optimal power flow problem.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the AC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type.\n\nKeywords\n\nJuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:\n\nbridge: manage the bridging mechanism (default: false),\nname: manage the creation of string names (default: true).\n\nAdditionally, users can modify variable names used for printing and writing through the keywords magnitude, angle, active, and reactive. For instance, users can choose magnitude = \"V\" and angle = \"θ\" to display equations in a more readable format.\n\nReturns\n\nThe function returns an instance of the ACOptimalPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The JuMP model, references to the variables, constraints, and objective.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/optimalPowerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function solves the AC optimal power flow model, computing the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.\n\nUpdates\n\nThe calculated active and reactive powers, as well as voltage magnitudes and angles, are stored in the power.generator and voltage fields of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingPrimal!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingPrimal!","text":"startingPrimal!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function retrieves the active and reactive power outputs of the generators, as well as the voltage magnitudes and angles from the PowerSystem composite type. It then assigns these values to the ACOptimalPowerFlow type, allowing users to initialize starting primal values as needed.\n\nUpdates\n\nThis function only updates the voltage and generator fields of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingPrimal!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingDual!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingDual!","text":"startingDual!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function removes all values of the dual variables.\n\nUpdates\n\nThis function only updates the dual field of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingDual!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#DC-Optimal-Power-Flow-2","page":"Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"dcOptimalPowerFlow\nsolve!(::PowerSystem, ::DCOptimalPowerFlow)\nstartingPrimal!(::PowerSystem, ::DCOptimalPowerFlow)\nstartingDual!(::PowerSystem, ::DCOptimalPowerFlow)","category":"page"},{"location":"api/optimalPowerFlow/#JuliaGrid.dcOptimalPowerFlow","page":"Optimal Power Flow","title":"JuliaGrid.dcOptimalPowerFlow","text":"dcOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name, angle, active)\n\nThe function sets up the optimization model for solving the DC optimal power flow problem.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the DC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.\n\nUpdates\n\nIf the DC model has not been created, the function automatically initiates an update within the dc field of the PowerSystem type.\n\nKeywords\n\nJuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:\n\nbridge: manage the bridging mechanism (default: false),\nname: manage the creation of string names (default: true).\n\nAdditionally, users can modify variable names used for printing and writing through the keywords angle and active. For instance, users can choose angle = \"θ\" to display equations in a more readable format.\n\nReturns\n\nThe function returns an instance of the DCOptimalPowerFlow type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angle,\npower: The variable allocated to store the active powers,\nmethod: The JuMP model, references to the variables, constraints, and objective.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/optimalPowerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function solves the DC optimal power flow model, computing the active power outputs of the generators, as well as the bus voltage angles.\n\nUpdates\n\nThe calculated active powers, as well as voltage angles, are stored in the power.generator and voltage fields of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingPrimal!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingPrimal!","text":"startingPrimal!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function retrieves the active power outputs of the generators and the bus voltage angles from the PowerSystem composite type. These values are then assigned to the DCOptimalPowerFlow type, enabling users to initialize starting primal values according to their requirements.\n\nUpdates\n\nThis function only updates the voltage and generator fields of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)\n\nstartingPrimal!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingDual!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingDual!","text":"startingDual!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function removes all values of the dual variables.\n\nUpdates\n\nThis function only updates the dual field of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)\n\nstartingDual!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"manual/acPowerFlow/#ACPowerFlowManual","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To perform the AC power flow analysis, we will first need the PowerSystem type that has been created with the AC model. Following that, we can construct the power flow model encapsulated within the ACPowerFlow type by employing one of the following functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"newtonRaphson,\nfastNewtonRaphsonBX,\nfastNewtonRaphsonXB,\ngaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These functions will set up the AC power flow framework. To obtain bus voltages and solve the power flow problem, we can use the following functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"mismatch!,\nsolve!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, the package provides two functions for reactive power limit validation of generators and adjusting the voltage angles to match an arbitrary bus angle:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"reactiveLimit!,\nadjustAngle!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the AC power flow solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses, branches, or generators:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses, branches, or generators.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#BusTypeModificationManual","page":"AC Power Flow","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Depending on how the system is constructed, the types of buses that are initially set are checked and can be changed during the construction of the ACPowerFlow type.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Assuming the Newton-Raphson method has been chosen, to explain the details, we can observe a power system:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddGenerator!(system; bus = \"Bus 2\")\n\nanalysis = newtonRaphson(system)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Initially, Bus 1 is set as the slack bus (type = 3), and Bus 2 and Bus 3 are generator buses (type = 2). However, Bus 3 does not have a generator, and JuliaGrid considers this a mistake and changes the corresponding bus to a demand bus (type = 1).","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After this step, JuliaGrid verifies the slack bus. Initially, the slack bus (type = 3) corresponds to Bus 1, but since it does not have an in-service generator connected to it, JuliaGrid recognizes it as another mistake. Therefore, JuliaGrid assigns a new slack bus from the available generator buses (type = 2) that have connected in-service generators. In this specific example, Bus 2 becomes the new slack bus.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid\n@default(unit)\n@default(template)\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddGenerator!(system; bus = \"Bus 2\")\n\nacModel!(system)\nanalysis = newtonRaphson(system)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As a result, we can observe the updated array of bus types:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Note that, if a bus is initially defined as the demand bus (type = 1) and later a generator is added to it, the bus type will not be changed to the generator bus (type = 2). Instead, it will remain as a demand bus.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nOnly the type of these buses that are defined as generator buses (type = 2) but do not have a connected in-service generator will be changed to demand buses (type = 1).The bus that is defined as the slack bus (type = 3) but lacks a connected in-service generator will have its type changed to the demand bus (type = 1). Meanwhile, the first generator bus (type = 2) with an in-service generator connected to it will be assigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#SetupStartingVoltagesManual","page":"AC Power Flow","title":"Setup Starting Voltages","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To begin analyzing the AC power flow in JuliaGrid, we must first establish the PowerSystem type. Once the power system is set up, we can select one of the available methods for solving the AC power flow problem, such as newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Assuming we have selected the Newton-Raphson method, we can use the following code snippet:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.0, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, magnitude = 0.9, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 2, magnitude = 0.8, angle = -0.2)\n\naddGenerator!(system; bus = \"Bus 1\", magnitude = 1.3)\naddGenerator!(system; bus = \"Bus 2\", magnitude = 1.1)\naddGenerator!(system; bus = \"Bus 3\", magnitude = 1.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, the function newtonRaphson generates starting voltage vectors in polar coordinates.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage magnitudes are set to:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This vector is created based on the bus types by selecting voltage magnitude values from the PowerSystem type, using the vectors:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"[system.bus.voltage.magnitude system.generator.voltage.magnitude]","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage angles are set to:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This vector is derived from the voltage angle values in the PowerSystem type:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system.bus.voltage.angle","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe rule governing the specification of starting voltage magnitudes is simple. If a bus has an in-service generator and is declared the generator bus (type = 2), then the starting voltage magnitudes are specified using the setpoint provided within the generator. This is because the generator bus has known values of voltage magnitude that are specified within the generator.On the other hand, the slack bus (type = 3) always requires an in-service generator. The starting value of the voltage magnitude at the slack bus is determined exclusively by the setpoints provided within the generators connected to it. This is a result of the slack bus having a known voltage magnitude that must be maintained.If there are multiple generators connected to the generator or slack bus, the initial voltage magnitude will align with the magnitude setpoint specified for the first in-service generator in the list.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Custom-Starting-Voltages","page":"AC Power Flow","title":"Custom Starting Voltages","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This method of specifying starting values has a significant advantage in that it allows the user to easily change the starting voltage magnitudes and angles, which play a crucial role in iterative methods. For instance, suppose we define our power system as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.0, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, magnitude = 0.9, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 2, magnitude = 0.8, angle = -0.2)\n\naddGenerator!(system; bus = \"Bus 1\", magnitude = 1.1)\naddGenerator!(system; bus = \"Bus 3\", magnitude = 1.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, the user can initiate a \"flat start\", this can be easily done as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for i = 1:system.bus.number\n system.bus.voltage.magnitude[i] = 1.0\n system.bus.voltage.angle[i] = 0.0\nend\n\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage values are:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Consequently, the iteration begins with a fixed set of voltage magnitude values that remain constant throughout the iteration process. The remaining values are initialized as part of the \"flat start\" approach.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerFlowSolutionManual","page":"AC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To start, we will create a power system and define the AC model by invoking the acModel! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\n\n@generator(active = 3.2)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", magnitude = 1.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the AC model is defined, we can choose the method to solve the power flow problem. JuliaGrid provides four methods: newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, and gaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For example, to use the Newton-Raphson method to solve the power flow problem, we can use:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, the user activates LU factorization to solve the system of linear equations within each iteration of the Newton-Raphson method. However, users can specifically opt for the QR factorization method:analysis = newtonRaphson(system, QR)The capability to change the factorization method is exclusively available for the Newton-Raphson and fast Newton-Raphson methods.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This function sets up the desired method for an iterative process based on two functions: mismatch! and solve!. The mismatch! function calculates the active and reactive power injection mismatches using the given voltage magnitudes and angles, while solve! computes the voltage magnitudes and angles.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To perform an iterative process with the Newton-Raphson or fast Newton-Raphson methods in JuliaGrid, the mismatch! function must be included inside the iteration loop. For instance:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Upon completion of the AC power flow analysis, the solution is conveyed through the bus voltage magnitudes and angles. Here are the values corresponding to the buses:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In contrast, the iterative loop of the Gauss-Seidel method does not require the mismatch! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = gaussSeidel(system)\nfor iteration = 1:100\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In these examples, the algorithms run until the specified number of iterations is reached.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nWe recommend that the reader refer to the tutorial on AC Power Flow Analysis, where we explain the implementation of the methods and algorithm structures in detail.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Breaking-the-Iterative-Process","page":"AC Power Flow","title":"Breaking the Iterative Process","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can terminate the iterative process using the mismatch! function. The following code shows an example of how to use the function to break out of the iteration loop:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, rad, V) # hide\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n println(\"Solution Found.\")\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The mismatch! function returns the maximum absolute values of active and reactive power injection mismatches, which are commonly used as a convergence criterion in iterative AC power flow algorithms. Note that the function can also be used to terminate the loop when using the Gauss-Seidel method, even though it is not required.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nTo ensure an accurate count of iterations, the user should place the iteration counter after the condition expressions within the if construct.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Combining-Methods","page":"AC Power Flow","title":"Combining Methods","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The PowerSystem type, once created, can be shared among different methods, offering several advantages.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For instance, while the Gauss-Seidel method is commonly used to swiftly derive an approximate solution, the Newton-Raphson method is favored for obtaining precise final solutions. Hence, a strategy involves employing the Gauss-Seidel method for a limited number of iterations, followed by initializing the Newton-Raphson method with the voltages obtained from the Gauss-Seidel method, leveraging it as a starting point for further refinement:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"gs = gaussSeidel(system)\nfor iteration = 1:5\n solve!(system, gs)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, we can initialize the Newton-Raphson method with the voltages obtained from the Gauss-Seidel method and start the algorithm from that point:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = gs.voltage.magnitude[i]\n analysis.voltage.angle[i] = gs.voltage.angle[i]\nend\n\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe functions newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel only modify the PowerSystem type to eliminate mistakes in the bus types as explained in the section Bus Type Modification. Further, the functions mismatch! and solve! do not modify the PowerSystem type at all. Therefore, it is safe to use the same PowerSystem type for multiple analyses once it has been created.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Print-Results-in-the-REPL","page":"AC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Save-Results-to-a-File","page":"AC Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Save-Results-to-a-CSV-File","page":"AC Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusData(system, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerSystemAlterationManual","page":"AC Power Flow","title":"Power System Update","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After establishing the PowerSystem type using the powerSystem function and configuring the AC model with acModel!, users gain the capability to incorporate new branches and generators. Furthermore, they can adjust buses, branches, and generators.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once updates are done, users can progress towards generating the ACPowerFlow type using the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function. Ultimately, resolving the AC power flow is achieved through the utilization of the mismatch! and solve! functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1, active = 3.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the defined power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\n\nupdateBus!(system; label = \"Bus 2\", active = 0.2)\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system; label = \"Branch 1\", status = 0)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nupdateGenerator!(system; label = \"Generator 1\", active = 0.3)\n\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the updated power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate the PowerSystem within the ac field from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerFlowUpdateManual","page":"AC Power Flow","title":"Power Flow Update","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"An advanced methodology involves users establishing the ACPowerFlow type using newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel just once. After this initial setup, users can integrate new branches and generators, and also have the capability to modify buses, branches, and generators, all without the need to recreate the ACPowerFlow type.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This advancement extends beyond the previous scenario where recreating the PowerSystem and AC model was unnecessary, to now include the scenario where ACPowerFlow also does not need to be recreated. Such efficiency proves particularly beneficial in cases where JuliaGrid can reuse established Jacobian matrices or even factorizations, especially when users choose the fast Newton-Raphson method.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"By modifying the previous example, we observe that we now create the ACPowerFlow type only once using the newtonRaphson function. This approach allows us to circumvent the need for reinitializing the Jacobian matrix, enabling us to proceed directly with iterations:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1, active = 3.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the defined power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\n\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.2)\n\naddBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system, analysis; label = \"Branch 1\", status = 0)\n\naddGenerator!(system, analysis; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 0.3)\n\n# <- No need for re-build; we have already updated the existing ACPowerFlow instance\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate both the PowerSystem within the ac field and the ACPowerFlow from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Fast-Newton-Raphson:-Reusing-Jacobian-Matrices-Factorizations","page":"AC Power Flow","title":"Fast Newton-Raphson: Reusing Jacobian Matrices Factorizations","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"An intriguing scenario unfolds when employing the fast Newton-Raphson method. Continuing from the previous example, let us now initialize the fast Newton-Raphson method and proceed with iterations as outlined below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = fastNewtonRaphsonBX(system)\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Throughout this process, JuliaGrid will factorize the constant Jacobian matrices that govern the fast Newton-Raphson method.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, let us make changes to the power system and proceed directly to the iteration step:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", reactive = 0.02)\nupdateGenerator!(system, analysis; label = \"Generator 1\", reactive = 0.1)\n\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nIn this scenario, JuliaGrid identifies cases where the user has not altered parameters that impact the Jacobian matrices. Consequently, JuliaGrid efficiently utilizes the previously performed factorizations, leading to a notably faster solution compared to recomputing the factorization process.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Warm-Start","page":"AC Power Flow","title":"Warm Start","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In these scenarios, users leverage the previously created PowerSystem type with the AC model and also reuse the ACPowerFlow type, proceeding directly to the iterations. This approach offers the advantage of a \"warm start\", wherein the initial voltages for the subsequent iteration step align with the solution from the previous iteration step. This alignment facilitates an efficient continuation of the power flow analysis.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Let us now make another alteration to the power system:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", active = 0.1, magnitude = 0.95, angle = -0.07)\nupdateGenerator!(system, analysis; label = \"Generator 2\", reactive = 0.2, magnitude = 1.1)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"With these modifications we are not only altering the power system, but also starting voltages. For the next uses of one of the methods, these values now are:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Therefore, users possess the flexibility to adjust these initial values as needed by employing the magnitude and angle keywords within the updateBus! and updateGenerator! functions.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"If users prefer to set starting voltages according to the typical scenario, they can accomplish this through the startingVoltage! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"startingVoltage!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, we have starting voltages defined exclusively according to the PowerSystem. These values are exactly the same as if we executed the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function after all the updates we performed:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Limitations","page":"AC Power Flow","title":"Limitations","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function oversees bus type validations, as outlined in the Bus Type Modification section. Consequently, attempting to change bus types or leaving generator buses without a generator and then proceeding directly to the iteration process is not viable.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In such scenarios, JuliaGrid will raise an error:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", type = 2)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In this scenario, the user must execute the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function instead of trying to reuse them, for example:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system; label = \"Bus 2\", type = 2)\n\nanalysis = fastNewtonRaphsonBX(system)\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nAfter creating the PowerSystem and ACPowerFlow types, users can add or modify buses, branches, and generators before directly proceeding to iterations. JuliaGrid automatically executes the necessary functions when adjustments lead to a valid solution. However, if modifications are incompatible, like altering bus types, JuliaGrid raises an error to prevent misleading outcomes, ensuring accuracy.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerCurrentAnalysisManual","page":"AC Power Flow","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the solution from the AC power flow, we can calculate various electrical quantities related to buses, branches, and generators using the power! and current! functions. For instance, let us consider the power system for which we obtained the AC power flow solution:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.6)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.1, susceptance = 0.03)\naddBus!(system; label = \"Bus 3\", type = 1, conductance = 0.02)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.4)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.0, reactive = 0.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For instance, if we want to show the active power injections and the to-bus current angles, we can employ the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.to.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nTo better understand the powers and currents associated with buses, branches, and generators that are obtained by the power! and current! functions, we suggest referring to the tutorials on AC Power Flow Analysis.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Print-Results-in-the-REPL-2","page":"AC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus summary with the desired units, users can use the following function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nprintBusSummary(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Injection","page":"AC Power Flow","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC Power Flow","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC Power Flow","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 3\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Flow","page":"AC Power Flow","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the functions provided below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC Power Flow","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC Power Flow","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Generator-Active-and-Reactive-Power-Output","page":"AC Power Flow","title":"Generator Active and Reactive Power Output","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can compute the active and reactive power output of a particular generator using the function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = generatorPower(system, analysis; label = \"Generator 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Injection","page":"AC Power Flow","title":"Current Injection","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Flow","page":"AC Power Flow","title":"Current Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Through-Series-Impedance","page":"AC Power Flow","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#GeneratorReactivePowerLimitsManual","page":"AC Power Flow","title":"Generator Reactive Power Limits","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function reactiveLimit! can be used to check if the generators' output of reactive power is within the defined limits after obtaining the solution from the AC power flow analysis:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\naddBus!(system; label = \"Bus 3\", type = 2, reactive = 0.05)\naddBus!(system; label = \"Bus 4\", type = 2, reactive = 0.05)\n\n@branch(resistance = 0.015)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 4\", reactance = 0.004)\n\n@generator(minReactive = -0.4, maxReactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\")\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", reactive = 0.8)\naddGenerator!(system; label = \"Generator 3\", bus = \"Bus 4\", reactive = 0.9)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nviolate = reactiveLimit!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The output reactive power of the observed generators is subject to limits which are defined as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"[system.generator.capability.minReactive system.generator.capability.maxReactive]","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the solution of the AC power flow analysis, the reactiveLimit! function is used to internally calculate the output powers of the generators and verify if these values exceed the defined limits. Consequently, the variable violate indicates whether there is a violation of limits.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In the provided example, it can be observed that the Generator 2 and Generator 3 violate the maximum limit:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.generator.label, violate)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Due to these violations of limits, the PowerSystem type undergoes modifications, and the output reactive power at the limit-violating generators is adjusted as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.generator.label, system.generator.output.reactive)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To ensure that these values stay within the limits, the bus type must be changed from the generator bus (type = 2) to the demand bus (type = 1), as shown below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After modifying the PowerSystem type as described earlier, we can run the simulation again with the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the simulation is complete, we can verify that all generator reactive power outputs now satisfy the limits by checking the violate variable again:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"violate = reactiveLimit!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe reactiveLimit! function changes the PowerSystem type deliberately because it is intended to help users create the power system where all reactive power outputs of the generators are within limits.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#New-Slack-Bus","page":"AC Power Flow","title":"New Slack Bus","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Looking at the following code example, we can see that the output limits of the generator are set only for Generator 1 that is connected to the slack bus:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, reactive = 0.05)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\naddBus!(system; label = \"Bus 3\", type = 2)\naddBus!(system; label = \"Bus 4\", type = 2)\n\n@branch(resistance = 0.01)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 4\", reactance = 0.004)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", maxReactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 4\", reactive = 0.3)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Upon checking the limits, we can observe that the slack bus has been transformed by executing the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"violate = reactiveLimit!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, the generator connected to the slack bus is violating the minimum reactive power limit, which indicates the need to convert the slack bus. It is important to note that the new slack bus can be created only from the generator bus (type = 2). We will now perform another AC power flow analysis on the modified system using the following:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After examining the bus voltages, we will focus on the angles:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can observe that the angles have been calculated based on the new slack bus. JuliaGrid offers the function to adjust these angles to match the original slack bus as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"adjustAngle!(system, analysis; slack = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After executing the above code, the updated results can be viewed:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/#ACStateEstimationManual","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To perform nonlinear or AC state estimation, the initial requirement is to have the PowerSystem type configured with the AC model, along with the Measurement type storing measurement data. Next, we can develop either the weighted least-squares (WLS) model, utilizing the Gauss-Newton method, or the least absolute value (LAV) model. These models are encapsulated within the ACStateEstimation type:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"gaussNewton,\nacLavStateEstimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For resolving the AC state estimation problem and obtaining bus voltage magnitudes and angles, utilize the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"solve!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After executing the function solve!, where the user employs the Gauss-Newton method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Moreover, before the creating ACStateEstimation type, users can initiate observability analysis to identify observable islands and restore observability by employing:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islandTopologicalFlow,\nislandTopological,\nrestorationGram!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After obtaining the AC state estimation solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses and branches:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses or branches.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEBusTypeModificationManual","page":"AC State Estimation","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In AC state estimation, it is necessary to designate a slack bus, where the bus voltage angle is known. Therefore, when establishing the ACStateEstimation type, the initially assigned slack bus is evaluated and may be altered. If the designated slack bus (type = 3) lacks a connected in-service generator, it will be changed to a demand bus (type = 1). Conversely, the first generator bus (type = 2) with an active in-service generator linked to it will be reassigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEObservabilityAnalysisManual","page":"AC State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To initiate the power system with measurements at specific locations, follow the provided example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.5, reactive = 0.01)\naddBus!(system; label = \"Bus 4\", type = 1, active = 0.2, reactive = 0.02)\naddBus!(system; label = \"Bus 5\", type = 1, active = 0.3, reactive = 0.03)\naddBus!(system; label = \"Bus 6\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 7\", type = 1, active = 0.1, reactive = 0.01)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.002)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 5\", reactance = 0.02)\naddBranch!(system; label = \"Branch 4\", from = \"Bus 3\", to = \"Bus 4\", reactance = 0.03)\naddBranch!(system; label = \"Branch 5\", from = \"Bus 5\", to = \"Bus 6\", reactance = 0.05)\naddBranch!(system; label = \"Branch 6\", from = \"Bus 3\", to = \"Bus 5\", reactance = 0.05)\naddBranch!(system; label = \"Branch 7\", from = \"Bus 6\", to = \"Bus 7\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 4.2, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", active = 0.2, reactive = 0.1)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 1.15)\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = -0.50)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 4\", active = 0.20)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 4\", reactive = -0.02)\n\naddWattmeter!(system, device; label = \"Wattmeter 3\", from = \"Branch 5\", active = -0.20)\naddVarmeter!(system, device; label = \"Varmeter 3\", from = \"Branch 5\", reactive = 0.02)\n\naddWattmeter!(system, device; label = \"Wattmeter 4\", bus = \"Bus 2\", active = -0.1)\naddVarmeter!(system, device; label = \"Varmeter 4\", bus = \"Bus 2\", reactive = -0.01)\n\naddWattmeter!(system, device; label = \"Wattmeter 5\", bus = \"Bus 3\", active = -0.30)\naddVarmeter!(system, device; label = \"Varmeter 5\", bus = \"Bus 3\", reactive = 0.66)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Attempting to solve this system immediately may not be possible because the gain matrix will be singular. To avoid this situation, users can perform observability analysis.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid employs standard observability analysis performed on the linear decoupled measurement model. Active power measurements from wattmeters are utilized to estimate bus voltage angles, while reactive power measurements from varmeters are used to estimate bus voltage magnitudes. This necessitates that measurements of active and reactive power come in pairs.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Observability Analysis for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"However, the initial step involves defining observable islands. JuliaGrid offers users two options for obtaining observable islands: flow observable islands or maximal observable islands. The selection depends on the power system's structure and available measurements. Identifying only flow observable islands reduces complexity in the island detection function, but increases complexity in the restoration function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Flow-Observable-Islands","page":"AC State Estimation","title":"Flow Observable Islands","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, let us identify flow observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopologicalFlow(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, four flow observable islands are identified: Bus 1 and Bus 2 form the first island, Bus 3 and Bus 4 form the second island, Bus 5 and Bus 6 constitute the third island, while Bus 7 forms the fourth island:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Maximal-Observable-Islands","page":"AC State Estimation","title":"Maximal Observable Islands","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we will instruct the user on obtaining maximal observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome reveals the identification of two maximal observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is evident that upon comparing this result with the flow islands, the merging of the two injection measurements at Bus 2 and Bus 3 consolidated the first, second, and third flow observable islands into a single island.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Restore-Observability","page":"AC State Estimation","title":"Restore Observability","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Before commencing the restoration of observability in the context of the linear decoupled measurement model and observability analysis, it is imperative to ensure that the system possesses one bus voltage magnitude measurement. This necessity arises from the fact that observable islands are identified based on wattmeters, where wattmeters are tasked with estimating voltage angles. Since one voltage angle is already known from the slack bus, the same principle should be applied to bus voltage magnitudes. Therefore, to address this requirement, we add:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user needs to establish a set of pseudo-measurements, where measurements must come in pairs as well. Let us create that set:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"pseudo = measurement()\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 1\", bus = \"Bus 1\", active = 0.31)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 1\", bus = \"Bus 1\", reactive = -0.19)\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 2\", from = \"Branch 7\", active = 0.10)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 2\", from = \"Branch 7\", reactive = 0.01)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThe labels for specific pseudo-measurements must differ from those defined in the measurements stored in the device set. This is necessary because the next step involves adding pseudo-measurements to the device set.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user can execute the restorationGram! function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"restorationGram!(system, device, pseudo, islands)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This function attempts to restore observability using pseudo-measurements. As a result, the inclusion of measurements from Pseudo-Wattmeter 2 and Pseudo-Varmeter 2 facilitates observability restoration, and these measurements are subsequently added to the device variable:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device.wattmeter.label\ndevice.varmeter.label\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, the power system becomes observable, allowing the user to proceed with forming the AC state estimation model and solving it. Ensuring the observability of the system does not guarantee obtaining accurate estimates of the state variables. Numerical ill-conditioning may adversely impact the state estimation algorithm. However, in most cases, efficient estimation becomes feasible when the system is observable [2].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, it is worth mentioning that restoration might encounter difficulties due to the default zero pivot threshold set at 1e-5. This threshold can be modified using the restorationGram! function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nDuring the restoration step, if users define bus phasor measurements, these measurements will be considered. Consequently, the system may achieve observability even if multiple islands persist.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACLSStateEstimationSolutionManual","page":"AC State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To begin, we will define the PowerSystem and Measurement types:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\")\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-2)\n\n@ammeter(label = \"Ammeter ? (!)\")\naddAmmeter!(system, device; from = \"Branch 3\", magnitude = 0.947, variance = 1e-1)\naddAmmeter!(system, device; to = \"Branch 2\", magnitude = 1.674, variance = 1e-1)\n\n@wattmeter(label = \"Wattmeter ? (!)\")\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1, variance = 2e-3)\n\n@varmeter(label = \"Varmeter ? (!)\")\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059, variance = 1e-4)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, to establish the AC state estimation model, we will utilize the gaussNewton function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the system of linear equations within each iteration of the Gauss-Newton method. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = gaussNewton(system, device, LDLt)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Setup-Starting-Voltages","page":"AC State Estimation","title":"Setup Starting Voltages","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The initial voltages for the Gauss-Newton method are determined based on the specified initial voltage magnitudes and angles within the buses of the PowerSystem type. These values are then forwarded to the ACStateEstimation during the execution of the gaussNewton function. Therefore, the starting voltages in this example are as follows:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the flexibility to modify these vectors according to their own requirements in order to adjust the starting voltages. For instance, users can conduct an initial AC power flow analysis and utilize the obtained solution as the starting voltages for AC state estimation:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"powerFlow = newtonRaphson(system)\nfor iteration = 1:10\n mismatch!(system, powerFlow)\n solve!(system, powerFlow)\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = powerFlow.voltage.magnitude[i]\n analysis.voltage.angle[i] = powerFlow.voltage.angle[i]\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#State-Estimator","page":"AC State Estimation","title":"State Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To conduct an iterative process using the Gauss-Newton method, it is essential to include the solve! function inside the iteration loop. For example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for iteration = 1:20\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once the state estimator is obtained, users can access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Breaking-the-Iterative-Process","page":"AC State Estimation","title":"Breaking the Iterative Process","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The iterative process can be terminated using the solve! function. The following code demonstrates how to utilize this function to break out of the iteration loop:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n println(\"Solution Found.\")\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The solve! function returns the maximum absolute values of the state variable increment, which are commonly used as a convergence criterion in the iterative Gauss-Newton algorithm.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on AC State Estimation for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Inclusion-of-PMUs-in-Rectangular-Coordinates","page":"AC State Estimation","title":"Inclusion of PMUs in Rectangular Coordinates","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the example above, our focus is solely on solving the AC state estimation using SCADA measurements. However, users have the option to also integrate PMUs into the AC state estimation, either in the rectangular or polar coordinate system.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The default approach is to include PMUs in the rectangular coordinate system:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; to = \"Branch 1\", magnitude = 1.05, angle = 3.047)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the case of the rectangular system, inclusion resolves ill-conditioned problems arising in polar coordinates due to small values of current magnitudes. However, this approach's main disadvantage is related to measurement errors, as measurement errors correspond to polar coordinates. Therefore, the covariance matrix must be transformed from polar to rectangular coordinates [3]. As a result, measurement errors of a single PMU are correlated, and the covariance matrix does not have a diagonal form. Despite that, the measurement error covariance matrix is usually considered as a diagonal matrix, affecting the accuracy of the state estimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the example above, we specifically include PMUs where measurement error correlations are disregarded. This is evident through the precision matrix, which maintains a diagonal form:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device);\nanalysis.method.precision","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Lastly, we incorporate correlation into our model by adding a new PMU with the desired error correlation:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 0.95, angle = -0.08, correlated = true)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, we can observe the precision matrix that does not hold a diagonal form:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device);\nanalysis.method.precision","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Inclusion-of-PMUs-in-Polar-Coordinates","page":"AC State Estimation","title":"Inclusion of PMUs in Polar Coordinates","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The second approach involves incorporating these measurements into the polar coordinate system. For instance:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; from = \"Branch 1\", magnitude = 1.048, angle = -0.057, polar = true)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This inclusion of PMUs provides more accurate state estimates compared to rectangular inclusion, but demands longer computing time. PMUs are handled in the same manner as SCADA measurements. However, this approach is susceptible to ill-conditioned problems arising in polar coordinates due to small values of current magnitudes [3, 4].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nIt is important to note that with each individual phasor measurement, we can set the coordinate system, providing flexibility to include some in polar and some in rectangular systems. This flexibility is particularly valuable because bus voltage phasor measurements are preferably included in a polar coordinate system, while current phasor measurements are best suited to a rectangular coordinate system.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Alternative-Formulation","page":"AC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device; label = \"PMU 2 (Bus 3)\", correlated = false)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, by specifying the Orthogonal argument in the gaussNewton function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device, Orthogonal)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Print-Results-in-the-REPL","page":"AC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Save-Results-to-a-File","page":"AC State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nWe also provide functions to print or save state estimation results, such as estimated values and residuals. For more details, users can consult the Power and Current Analysis section of this manual.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACBadDataDetectionManual","page":"AC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After acquiring the WLS solution using the Gauss-Newton method, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new measurement. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; from = \"Branch 2\", active = 31.1)\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we can observe the impact of the outlier on the solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the AC state estimation model:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective measurement as out-of-service within the Measurement type.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After removing bad data, a new estimate can be computed without considering this specific measurement. The user has the option to either restart the gaussNewton function or proceed directly to the iteration loop. However, if the latter option is chosen, using voltages obtained with outlier presence as the starting point could significantly impede algorithm convergence. To avoid this undesirable outcome, the user should first establish a new starting point and commence the iteration procedure. For instance:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for i = 1:system.bus.number\n analysis.voltage.magnitude[i] = system.bus.voltage.magnitude[i]\n analysis.voltage.angle[i] = system.bus.voltage.angle[i]\nend\n\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, we obtain a new solution devoid of the impact of the outlier measurement:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#PMULAVtateEstimationSolutionManual","page":"AC State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Setup-Starting-Primal-Values","page":"AC State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the ACStateEstimation type. By default, these values are initially established using the initial bus voltage magnitudes and angles from PowerSystem type:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Solution","page":"AC State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACMeasurementsAlterationManual","page":"AC State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the ACStateEstimation type using the gaussNewton or acLavStateEstimation function. Ultimately, resolving the AC state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\", variance = 1e-3)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\n\n@wattmeter(label = \"Wattmeter ? (!)\", varianceBus = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1)\n\n@varmeter(label = \"Varmeter ? (!)\", varianceFrom = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01)\n\n@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.976, angle = -0.052)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the defined model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924)\nupdateWattmeter!(system, device; label = \"Wattmeter 2 (Bus 2)\", variance = 1e-4)\n\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-5)\nupdateVarmeter!(system, device; label = \"Varmeter 2 (Bus 2)\", reactive = -0.011)\n\nupdatePmu!(system, device; label = \"PMU 1 (Bus 2)\", polar = false)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the updated model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACStateEstimationUpdateManual","page":"AC State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"An advanced methodology involves users establishing the ACStateEstimation type using gaussNewton or acLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the ACStateEstimation type.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where ACStateEstimation also does not need to be recreated.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of ACStateEstimation is not practical in terms of reusing this type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can modify the prior example to achieve the same model without establishing ACStateEstimation twice:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\", variance = 1e-3)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\n\n@wattmeter(label = \"Wattmeter ? (!)\", varianceBus = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1)\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924, status = 0)\n\n@varmeter(label = \"Varmeter ? (!)\", varianceFrom = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01)\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-5, status = 0)\n\n@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.976, angle = -0.052)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the defined model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 3 (From Branch 3)\", status = 1)\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 2 (Bus 2)\", variance = 1e-4)\n\nupdateVarmeter!(system, device, analysis; label = \"Varmeter 3 (To Branch 3)\", status = 1)\nupdateVarmeter!(system, device, analysis; label = \"Varmeter 2 (Bus 2)\", reactive = -0.011)\n\nupdatePmu!(system, device, analysis; label = \"PMU 1 (Bus 2)\", polar = false)\n\n# <- No need for re-build; we have already updated the existing ACStateEstimation instance\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the ACStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEPowerCurrentAnalysisManual","page":"AC State Estimation","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After obtaining the solution from the AC state estimation, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the model for which we obtained the AC state estimation solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, susceptance = 0.002)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046, variance = 1e-2)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924, variance = 1e-3)\n\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059, variance = 1e-3)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01, variance = 1e-2)\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-3)\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For instance, if we want to show the active power injections and the from-bus current angles, we can employ the following code:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nTo better understand the powers and currents associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on AC State Estimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Print-Results-in-the-REPL-2","page":"AC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can utilize any of the print functions outlined in the Print API. For example, to print state estimation data related to wattmeters, we can use:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@power(MW, pu, pu)\nprintWattmeterData(system, device, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Save-Results-to-a-CSV-File","page":"AC State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintWattmeterData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Injection","page":"AC State Estimation","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC State Estimation","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC State Estimation","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Flow","page":"AC State Estimation","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC State Estimation","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC State Estimation","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Injection","page":"AC State Estimation","title":"Current Injection","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Flow","page":"AC State Estimation","title":"Current Flow","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Through-Series-Impedance","page":"AC State Estimation","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"api/analysis/#PowerCurrentAnalysisAPI","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"In the following section, we have provided a list of functions that can be utilized for post-processing analysis. Once the voltage values are obtained through power flow analysis, optimal power flow analysis, or state estimation, these functions can be used to calculate power or current values. The specific procedures for computing these values depend on the chosen analysis, which are described in separate manuals for further information.","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"using JuliaGrid","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#AC-Power-Analysis","page":"Power and Current Analysis","title":"AC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!\ninjectionPower\nsupplyPower\nshuntPower\nfromPower\ntoPower\nseriesPower\nchargingPower\ngeneratorPower","category":"page"},{"location":"api/analysis/#AC-Current-Analysis","page":"Power and Current Analysis","title":"AC Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"current!\ninjectionCurrent\nfromCurrent\ntoCurrent\nseriesCurrent","category":"page"},{"location":"api/analysis/#DC-Power-Analysis","page":"Power and Current Analysis","title":"DC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!\ninjectionPower\nsupplyPower\nfromPower\ntoPower\ngeneratorPower","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#ACPowerAnalysisAPI","page":"Power and Current Analysis","title":"AC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!(::PowerSystem, ::ACPowerFlow)\ninjectionPower(::PowerSystem, ::AC)\nsupplyPower(::PowerSystem, ::ACPowerFlow)\nshuntPower(::PowerSystem, ::AC)\nfromPower(::PowerSystem, ::AC)\ntoPower(::PowerSystem, ::AC)\nseriesPower(::PowerSystem, ::AC)\nchargingPower(::PowerSystem, ::AC)\ngeneratorPower(::PowerSystem, ::ACPowerFlow)","category":"page"},{"location":"api/analysis/#JuliaGrid.power!-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.power!","text":"power!(system::PowerSystem, analysis::AC)\n\nThe function computes the active and reactive powers associated with buses, branches, and generators for AC analysis.\n\nUpdates\n\nThis function updates the power field of the AC abstract type by computing the following electrical quantities:\n\ninjection: Active and reactive power bus injections.\nsupply: Active and reactive power bus injections from the generators.\nshunt: Active and reactive power values associated with shunt element at each bus.\nfrom: Active and reactive power flows at the from-bus end of each branch.\nto: Active and reactive power flows at the to-bus end of each branch.\ncharging: Active and reactive power values linked with branch charging admittances for each branch.\nseries Active and reactive power losses through each branch series impedance.\ngenerator: Produced active and reactive power outputs of each generator (not for state estimation).\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.injectionPower","text":"injectionPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power injections associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = injectionPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.supplyPower-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.supplyPower","text":"supplyPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power injections from the generators associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = supplyPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.shuntPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.shuntPower","text":"shuntPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power values of the shunt element associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = shuntPower(system, analysis; label = 9)\n\n```\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.fromPower","text":"fromPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power flows at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = fromPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.toPower","text":"toPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power flows at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = toPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.seriesPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.seriesPower","text":"seriesPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power losses across the series impedance of a specific branch within the AC framework. The label keyword argument should correspond to an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = seriesPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.chargingPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.chargingPower","text":"chargingPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power values associated with the charging admittances of a specific branch in the AC framework. The label keyword argument must correspond to an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = chargingPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.generatorPower-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.generatorPower","text":"generatorPower(system::PowerSystem, analysis::AC)\n\nThe function returns the active and reactive powers associated with a specific generator in the AC framework. The label keyword argument must match an existing generator label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = generatorPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#ACCurrentAnalysisAPI","page":"Power and Current Analysis","title":"AC Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"current!(::PowerSystem, ::AC)\ninjectionCurrent(::PowerSystem, ::AC)\nfromCurrent(::PowerSystem, ::AC)\ntoCurrent(::PowerSystem, ::AC)\nseriesCurrent(::PowerSystem, ::AC)","category":"page"},{"location":"api/analysis/#JuliaGrid.current!-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.current!","text":"current!(system::PowerSystem, analysis::AC)\n\nThe function computes the currents in the polar coordinate system associated with buses and branches in the AC framework.\n\nUpdates\n\nThis function calculates various electrical quantities in the polar coordinate system:\n\ninjection: Current injections at each bus.\nfrom: Current flows at each from-bus end of the branch.\nto: Current flows at each to-bus end of the branch.\nseries: Current flows through the series impedance of the branch in the direction from the from-bus end to the to-bus end of the branch.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\ncurrent!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.injectionCurrent","text":"injectionCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current injection in the polar coordinate system associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = injectionCurrent(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.fromCurrent","text":"fromCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = fromCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.toCurrent","text":"toCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = toCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.seriesCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.seriesCurrent","text":"seriesCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system through series impedance associated with a specific branch in the direction from the from-bus end to the to-bus end of the branch within the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = seriesCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#DCPowerAnalysisAPI","page":"Power and Current Analysis","title":"DC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!(::PowerSystem, ::DCPowerFlow)\ninjectionPower(::PowerSystem, ::DCPowerFlow)\nsupplyPower(::PowerSystem, ::DCPowerFlow)\nfromPower(::PowerSystem, ::DC)\ntoPower(::PowerSystem, ::DC)\ngeneratorPower(::PowerSystem, ::DCPowerFlow)","category":"page"},{"location":"api/analysis/#JuliaGrid.power!-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.power!","text":"power!(system::PowerSystem, analysis::DC)\n\nThe function calculates the active power values related to buses, branches, and generators within the DC analysis framework.\n\nUpdates\n\nThis function updates the power field of the DC abstract type by computing the following electrical quantities:\n\ninjection: Active power injections at each bus.\nsupply: Active power injections from the generators at each bus.\nfrom: Active power flows at each from-bus end of the branch.\nto: Active power flows at each to-bus end of the branch.\ngenerator: Output active powers of each generator (excluding for state estimation).\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\npower!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.injectionPower","text":"injectionPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power injection associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\ninjection = injectionPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.supplyPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.supplyPower","text":"supplyPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power injection from the generators associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nsupply = supplyPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromPower-Tuple{PowerSystem, DC}","page":"Power and Current Analysis","title":"JuliaGrid.fromPower","text":"fromPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power flow at the from-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nfrom = fromPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toPower-Tuple{PowerSystem, DC}","page":"Power and Current Analysis","title":"JuliaGrid.toPower","text":"toPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power flow at the to-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nto = toPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.generatorPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.generatorPower","text":"generatorPower(system::PowerSystem, analysis::DC; label)\n\nThis function returns the output active power associated with a specific generator in the DC framework. The label keyword argument must match an existing generator label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\ngenerator = generatorPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"tutorials/dcStateEstimation/#DCStateEstimationTutorials","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the DC model:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, angle = 0.0)\naddBus!(system; label = 2, type = 1, active = 0.1)\naddBus!(system; label = 3, type = 1, active = 1.3)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.2)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.1)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.3)\naddGenerator!(system; label = 1, bus = 1, active = 3.2)\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of measurement devices mathcalM into the graph mathcalG. In typical scenarios, the DC state estimation model relies solely on active power measurements originating from the set of wattmeters mathcalP. However, we provide the option for users to include measurements from the set of PMUs barmathcalP. Specifically, we utilize only the PMUs installed at the buses barmathcalP_textb subset barmathcalP that measure bus voltage angles. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEModelTutorials","page":"DC State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In accordance with the DC Model, the DC state estimation is derived through the linearization of the non-linear model. In this linearized model, all bus voltage magnitudes are assumed to be V_i approx 1, i in mathcalN. Additionally, shunt elements and branch resistances are neglected. This simplification implies that the DC model disregards reactive powers and transmission losses, focusing solely on active powers. Consequently, the DC state estimation considers only bus voltage angles, represented as mathbf x equiv bm Theta, as the state variables. As a result, the total number of state variables is n-1, with one voltage angle corresponding to the slack bus.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Within the JuliaGrid framework for DC state estimation, the methodology encompasses both active power flow and injection measurements from the set mathcalP, along with bus voltage angle measurements represented by the set barmathcalP_textb. These measurements contribute to the construction of a linear system of equations:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz=mathbfh(bm Theta)+mathbfu","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathbfh(bm Theta)= h_1(bm Theta), dots, h_k(bm Theta)^T is the vector of linear measurement functions, mathbfz = z_1dotsz_k^mathrmT is the vector of measurement values, and mathbfu = u_1dotsu_k^mathrmT is the vector of uncorrelated measurement errors, and this defines the vector of measurement variances mathbfv = v_1dotsv_k^mathrmT, where k = mathcalM.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Therefore, the linear system of equations can be represented based on the specific devices from which measurements originate, whether wattmeters or PMUs:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginbmatrix\n mathbfz_mathcalP3pt\n mathbfz_barmathcalP_textb\n endbmatrix =\n beginbmatrix\n mathbfh_mathcalP(bm Theta)3pt\n mathbfh_barmathcalP_textb(bm Theta)\n endbmatrix +\n beginbmatrix\n mathbfu_mathcalP3pt\n mathbfu_barmathcalP_textb\n endbmatrix","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In summary, upon user definition of the measurement devices, each i-th measurement device is linked to the measurement function h_i(bm Theta), the corresponding measurement value z_i, and the measurement variance v_i.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Active-Power-Injection-Measurements","page":"DC State Estimation","title":"Active Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"When adding a wattmeter P_i in mathcalP at bus i in mathcalN, users specify that the wattmeter measures active power injection and define measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_i mathbfv_mathcalP = v_P_i mathbfh_mathcalP(bm Theta) = h_P_i(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₃\", bus = 3, active = -1.30, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, utilizing the DC Model, we derive the function defining the active power injection as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_i(bm Theta) = B_iitheta_i + sum_j in mathcalN_i setminus i B_ij theta_j + P_texttri + P_textshi","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathcalN_i setminus i contains buses incident to bus i, excluding bus i, with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_i(bm Theta)mathrm partial theta_i = B_ii \n cfracmathrm partialh_P_i(bm Theta)mathrm partial theta_j = B_ij\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#From-Bus-End-Active-Power-Flow-Measurements","page":"DC State Estimation","title":"From-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Additionally, when introducing a wattmeter at branch (ij) in mathcalE, users specify that the wattmeter measures active power flow. It can be positioned at the from-bus end, denoted as P_ij in mathcalP, specifying the measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_ij mathbfv_mathcalP = v_P_ij mathbfh_mathcalP(bm Theta) = h_P_ij(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₁₂\", from = 1, active = 0.28, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, the function describing active power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_ij(bm Theta) = cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ij(bm Theta)mathrm partial theta_i = cfrac1tau_ij x_ij \n cfracmathrm partialh_P_ij(bm Theta)mathrm partial theta_j = -cfrac1tau_ij x_ij\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#To-Bus-End-Active-Power-Flow-Measurements","page":"DC State Estimation","title":"To-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, a wattmeter can be placed at the to-bus end, denoted as P_ji in mathcalP, specifying the measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_ji mathbfv_mathcalP = v_P_ji mathbfh_mathcalP(bm Theta) = h_P_ji(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₂₁\", to = 1, active = -0.28, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Thus, the function describing active power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_ji(bm Theta) = -cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" cfracmathrm partialh_P_ji(bm Theta)mathrm partial theta_i = -cfrac1tau_ij x_ij \n cfracmathrm partialh_P_ji(bm Theta)mathrm partial theta_j = cfrac1tau_ij x_ij","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Bus-Voltage-Angle-Measurements","page":"DC State Estimation","title":"Bus Voltage Angle Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"If the user opts to include phasor measurements that measure bus voltage angle at bus i in mathcalN, denoted as theta_i in barmathcalP_textb, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_barmathcalP_textb = z_theta_i mathbfv_barmathcalP_textb = v_theta_i mathbfh_barmathcalP_textb(bm Theta) = h_theta_i(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1.0, angle = 0,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-6)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, the function defining the bus voltage angle measurement is straightforward:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_theta_i(bm Theta) = theta_i","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expression:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" cfracmathrm partialh_theta_i(bm Theta)mathrm partial theta_i=1","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEWLSStateEstimationTutorials","page":"DC State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The solution to the DC state estimation problem is determined by solving the linear weighted least-squares (WLS) problem, represented by the following formula:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf H^T bm Sigma^-1 mathbf H bm Theta = mathbf H^T bm Sigma^-1 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, mathbf z in mathbb R^k denotes the vector of measurement values, the vector mathbf c in mathbb R^k holds constant terms, mathbf H in mathbb R^k times (n-1) represents the coefficient matrix, and bm Sigma in mathbb R^k times k is the measurement error covariance matrix, where the diagonal elements hold measurement variances.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The inclusion of the vector mathbfc is necessary due to the fact that measurement functions associated with active power measurements may include constant terms, especially when there are non-zero shift angles of transformers or shunt elements in the system consuming active powers, as evident from the provided measurement functions.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Implementation","page":"DC State Estimation","title":"Implementation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuliaGrid initiates the DC state estimation framework by setting up the WLS model, as illustrated in the following:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Coefficient-Matrix","page":"DC State Estimation","title":"Coefficient Matrix","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Using the above-described equations, JuliaGrid forms the coefficient matrix mathbfH in mathbbR^k times (n-1):","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐇 = analysis.method.coefficient","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Each row in the matrix corresponds to a specific measurement. The first mathcalP rows correspond to wattmeters, ordered as users add wattmeters, while the last barmathcalP_textb rows correspond to PMUs, also in the order users add PMUs.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Precision-Matrix","page":"DC State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuliaGrid opts not to retain the covariance matrix bm Sigma but rather stores its inverse, the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. The order of these values corresponds to the description provided for the coefficient matrix. Users can access these values using the following command:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Mean-Vector","page":"DC State Estimation","title":"Mean Vector","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can access the vector mathbf z - mathbfc, which contains the means of Gaussian distributions describing each measurement, using the following command:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In the context of the power system, where phase-shifting transformers and shunt elements consuming active powers are absent, and the slack angle has a zero value, the vector mathbfc= mathbf0. Consequently, the vector of means holds values that are equal to the measurement values.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Estimate-of-State-Variables","page":"DC State Estimation","title":"Estimate of State Variables","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Once the model is established, we solve the WLS equation to derive the estimate of bus voltage angles:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\thatbm Theta = mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T bm Sigma^-1 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This process is executed using the solve! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The initial step involves the LU factorization of the gain matrix:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf G = mathbf H^T bm Sigma^-1 mathbf H = mathbf L mathbf U","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the gain matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Access to the factorized gain matrix is available through:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Finally, the estimated bus voltage angles hatbm Theta = hattheta_i, i in mathcalN, can be retrieved using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It is essential to note that the slack bus voltage angle is temporarily excluded from the gain matrix mathbf G during computation. It is important to emphasize that this internal handling does not alter the stored elements.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEOrthogonalWLSStateEstimationTutorials","page":"DC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can employ an alternative approach:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device, Orthogonal)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf H^T mathbf W mathbf H bm Theta = mathbf H^T mathbf W (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf H bm Theta = left(mathbf W^12 mathbf Hright)^T mathbf W^12 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH^T barmathbfH bm Theta = barmathbfH^T barmathbfz","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH = mathbf W^12 mathbf H barmathbfz = mathbf W^12 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"At this point, QR factorization is performed on the rectangular matrix:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH = mathbf W^12 mathbf H = mathbfQmathbfR","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Executing this procedure involves the solve! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain the solution, JuliaGrid avoids materializing the orthogonal matrix mathbfQ and proceeds to solve the system, resulting in the estimate of state variables hatbm Theta = hattheta_i, where i in mathcalN:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEBadDataTutorials","page":"DC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₁\", bus = 1, active = 13.1, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, we will construct the WLS state estimation model and solve it:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" r_i = z_i - h_i(hat bm Theta) i in mathcalM","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf H mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"is removed from the DC model and marked as out-of-service.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, we can immediately solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSELAVTutorials","page":"DC State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It can be demonstrated that the problem can be expressed as a linear programming problem. This section outlines the method as described in [5, Sec. 6.5]. To revisit, we consider the system of linear equations:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz=mathbfh(bm Theta)+mathbfu","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n textminimize mathbf a^T mathbf r\n textsubjectto mathbfz - mathbfHbm Theta - mathbfc =mathbf r\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, mathbf a in mathbb R^k is the vector with all entries equal to one, and mathbf r represents the vector of measurement residuals. Let bm eta be defined in a manner that ensures:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbf r preceq bm eta","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"and replace the above inequality with two equalities using the introduction of two non-negative slack variables mathbf q in mathbb R_ge 0^k and mathbf w in mathbb R_ge 0^k:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r - mathbf q = -bm eta \n mathbf r + mathbf w = bm eta\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Let us now define four additional non-negative variables:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" bm Theta_x in mathbb R_ge 0^n bm Theta_y in mathbb R_ge 0^n \n mathbf r_x in mathbb R_ge 0^k mathbf r_y in mathbb R_ge 0^k","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" bm Theta = bm Theta_x - bm Theta_y mathbf r = mathbf r_x - mathbf r_y\n mathbf r_x = cfrac12 mathbf q mathbf r_y = cfrac12 mathbf w","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r - 2mathbf r_x = -2bm eta \n mathbf r + 2 mathbf r_y = 2bm eta\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"that is:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r_x + mathbf r_y = bm eta mathbf r = mathbf r_x - mathbf r_y\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n textminimize mathbf a^T (mathbf r_x + mathbf r_y)\n textsubjectto mathbfH(bm Theta_x - bm Theta_y) + mathbf r_x - mathbf r_y = mathbfz - mathbfc \n bm Theta_x succeq mathbf 0 bm Theta_y succeq mathbf 0 \n mathbf r_x succeq mathbf 0 mathbf r_y succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"As a result, we obtain optimal values for the four additional non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" hatbm Theta = bm Theta_x - bm Theta_y","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can retrieve the estimated bus voltage angles hatbm Theta = hattheta_i, i in mathcalN, using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEPowerAnalysisTutorials","page":"DC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution from the DC state estimation, we can calculate powers related to buses and branches using the power! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Power-Injections","page":"DC State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Generator-Power-Injections","page":"DC State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can determine the active power supplied by generators to the buses by summing the active power injections and the active power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" P_textpi = P_i + P_textdi i in mathcalN","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The vector of active power injected by generators into the buses, denoted by mathbfP_textp = P_textpi, can be obtained using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Power-Flows","page":"DC State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resulting active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, the resulting active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"tutorials/powerSystemModel/#ACDCModelTutorials","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Power system analyses commonly utilize the unified branch model that provides linear relationships between voltages and currents. However, as the focus is on power calculations rather than current calculations, the resulting equations become nonlinear, posing challenges in solving them [6]. Hence, to accurately analyze power systems without any approximations, we use the AC model, which is a crucial component of our framework. In contrast, to obtain a linear system of equations for various DC analyses, we introduce approximations in the unified branch model, resulting in the DC model.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIn this section, we not only describe the AC and DC models derived from the unified branch model but also furnish the power and current equations utilized in all JuliaGrid analyses.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"A common way to describe the power system network topology is through the bus/branch model, which employs the two-port pi-model, which results in the unified branch model. The bus/branch model can be represented by a graph denoted by mathcalG = (mathcalN mathcalE), where the set of nodes mathcalN = 1 dots n corresponds to buses, and the set of edges mathcalE subseteq mathcalN times mathcalN represents the branches of the power network.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us now construct the power system:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7, reactive = 12.7)\naddBus!(system; label = 3, type = 2, conductance = 2.1, susceptance = 1.2)\n\naddBranch!(system; from = 1, to = 2, resistance = 0.02, reactance = 0.06, susceptance = 0.05)\naddBranch!(system; from = 2, to = 3, reactance = 0.21, turnsRatio = 0.98, shiftAngle = 1.2)\n\naddGenerator!(system; bus = 1, active = 40.0, reactive = 42.4)\nnothing #hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The given example provides the set of buses mathcalN and the set of branches mathcalE:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_ij, where a_ij represents the generic element associated with the branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#ACModelTutorials","page":"Power System Model","title":"AC Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid is based on common network elements and benefits from the unified branch model to perform various analyses based on the system of nonlinear equations. To generate matrices and vectors for AC or nonlinear analysis, JuliaGrid employs the acModel! function:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"acModel!(system)\nnothing #hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#UnifiedBranchModelTutorials","page":"Power System Model","title":"Unified Branch Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The equivalent unified pi-model for a branch (ij) in mathcalE incident to the buses ij in mathcalN is shown in Figure 1.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 1: The equivalent branch model, where the transformer is located at the from-bus end of the branch.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe directions of the currents barI_ij, barI_ji, barI_textsi, and barI_textsj are vital for power flow analysis. Positive power aligns with the assumed current direction, moving away from the bus, while negative power implies a reverse flow towards the bus. JuliaGrid consistently uses these directions, along with barI_textlij, for power and current calculations.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch series admittance y_ij is inversely proportional to the branch series impedance z_ij:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" y_ij = frac1z_ij = frac1r_ij + textjx_ij =\n fracr_ijr_ij^2 + x_ij^2 - textjfracx_ijr_ij^2 + x_ij^2 = g_ij + textjb_ij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where r_ij is a resistance, x_ij is a reactance, g_ij is a conductance and b_ij is a susceptance of the branch.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vectors of resistances, denoted by mathbfr = r_ij, and reactances, denoted by mathbfx = x_ij, are stored in the variables:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐫 = system.branch.parameter.resistance\n𝐱 = system.branch.parameter.reactance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, the ac field stores the computed vector of branch series admittances mathbfy = y_ij:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲 = system.model.ac.admittance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch shunt admittance y_textsij is equal to:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"y_textsij = g_textsij + textjb_textsij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where g_textsij represents the shunt conductance of the branch, and b_textsij represents the shunt susceptance. Both of these values are positive for real line sections. It is worth noting that while the shunt conductance g_textsij is often insignificantly small and can be ignored in many cases, it is included in the analyses to ensure comprehensive consideration of all potential scenarios.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Within JuliaGrid, the total shunt conductances and susceptances of branches are stored. In order to obtain the vectors mathbfg_texts = g_textsij and mathbfb_texts = b_textsij, the conductances and susceptances must be distributed by considering the ends of the branches:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐠ₛ = 0.5 * system.branch.parameter.conductance\n𝐛ₛ = 0.5 * system.branch.parameter.susceptance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The transformer complex ratio alpha_ij is defined:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" alpha_ij = cfrac1tau_ije^-textjphi_ij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where tau_ij neq 0 is a transformer turns ratio, while phi_ij is a transformer phase shift angle, always located at the from-bus end of the branch. Note, if tau_ij = 1 and phi_ij = 0 the model describes the line. In-phase transformers are defined if tau_ij neq 1, phi_ij = 0, and y_textsij = 0, while phase-shifting transformers are obtained if tau_ij neq 1, phi_ij neq 0, and y_textsij = 0.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"These transformer parameters are stored in the vectors bmtau = tau_ij and bmphi = phi_ij, respectively:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝛕 = system.branch.parameter.turnsRatio\n𝚽 = system.branch.parameter.shiftAngle","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchShuntElementsTutorials","page":"Power System Model","title":"Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The currents flowing through shunt admittances denoted as y_textsij are defined as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_textsi = alpha_ij y_textsijbarV_i (ij) in mathcalE \n barI_textsj = y_textsijbarV_j (ij) in mathcalE\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"With these specified currents in place, it becomes straightforward to compute both the total active and reactive power that branch shunt elements demand and inject concerning the power system:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textsij = P_textsij + textjQ_textsij = alpha_ij barV_i barI_textsi^* + barV_j barI_textsj^* = y_textsij^*(alpha_ij^2 V_i^2 + V_j^2) (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For real branch sections, the reactive power is negative, Q_textsij 0, signifying that the branch injects reactive power due to its capacitive nature. The negative sign implies that the power flow direction opposes the assumed direction set by the currents barI_textsi and barI_textsj. The active power P_textsij represents active losses within the branch shunt admittances.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchSeriesElementTutorials","page":"Power System Model","title":"Branch Series Element","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The current flowing through a series admittance, denoted as y_ij, is defined as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" barI_textlij = alpha_ij y_ijbarV_i - y_ijbarV_i (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Consequently, the active and reactive powers associated with the branch series element are as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textlij = P_textlij + textjQ_textlij = (alpha_ij barV_i - barV_j) barI_textlij^* = y_ij^* (alpha_ij barV_i - barV_j) (alpha_ij barV_i - barV_j)^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power P_textlij accounts for losses originating from the resistance r_ij of the branch, while the reactive power Q_textlij represents losses resulting from the inductive characteristics of the impedance defined by reactance x_ij. This can be observed when the reactive power is positive Q_textlij 0.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchNetworkEquationsTutorials","page":"Power System Model","title":"Branch Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Using Kirchhoff's circuit laws, the branch model can be described by complex expressions:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_ij barI_ji\n endbmatrix =\n beginbmatrix\n cfrac1tau_ij^2(y_ij + y_textsij) -alpha_ij^*y_ij\n -alpha_ijy_ij y_ij + y_textsij\n endbmatrix\n beginbmatrix\n barV_i barV_j\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The admittance parameters are stored in the vectors mathbfy_textii = (y_ij + y_textsij) tau_ij^2, mathbfy_textij = -alpha_ij^*y_ij, mathbfy_textji = -alpha_ijy_ij, and mathbfy_textjj = y_ij + y_textsij and can be found in the variables:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲ᵢᵢ = system.model.ac.nodalFromFrom\n𝐲ᵢⱼ = system.model.ac.nodalFromTo\n𝐲ⱼᵢ = system.model.ac.nodalToFrom\n𝐲ⱼⱼ = system.model.ac.nodalToTo","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this context, we have easily derived the active and reactive power flow at the from-bus end of the branch:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_ij = P_ij + textjQ_ij = barV_i leftcfrac1tau_ij^2(y_ij + y_textsij) barV_i - alpha_ij^*y_ij barV_jright^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, we can determine the active and reactive power flow at the to-bus end of the branch:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_ji = P_ji + textjQ_ji = barV_j left-alpha_ijy_ij barV_i + (y_ij + y_textsij) barV_jright^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Positive values of active or reactive power, P_ij 0 or Q_ij 0, indicate power flow originating from the from-bus and moving towards the to-bus, following the direction of the current barI_ij. Conversely, negative values, P_ij 0 or Q_ij 0, signify power flow in the opposite direction. The same principles apply to P_ji 0 or Q_ji 0, indicating power flow from the to-bus to the from-bus, aligned with the current barI_ji, while negative values, P_ji 0 or Q_ji 0, denote the reverse flow direction.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#NodalNetworkEquationsTutorials","page":"Power System Model","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us consider an illustrative example from our case study, depicted in Figure 2. This example provides a smooth transition to the general case, demonstrating a system with three buses represented as mathcalN = 1 2 3 and two branches mathcalE = (1 2) (2 3), where bus 2 is incident to the shunt element with admittance y_textsh2.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 2: The example of the system with three buses and two branches.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe current barI_textsh2 follows the convention of coming out from the bus in terms of its direction. When calculating powers related to shunt elements, this current direction is assumed. Therefore, in cases where power is positive, it signifies alignment with the assumed current direction, emerging away from the bus. Conversely, when power is negative, the direction is reversed, indicating a flow towards the bus.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"According to the Branch Network Equations each branch is described using the system of equations as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_12 barI_21\n endbmatrix =\n beginbmatrix\n cfrac1tau_12^2(y_12 + y_texts12) -alpha_12^*y_12\n -alpha_12y_12 y_12 + y_texts12\n endbmatrix\n beginbmatrix\n barV_1 barV_2\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_23 barI_32\n endbmatrix =\n beginbmatrix\n cfrac1tau_23^2(y_23 + y_texts23) -alpha_23^*y_23\n -alpha_23y_23 y_23 + y_texts23\n endbmatrix\n beginbmatrix\n barV_2 barV_3\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The complex current injections at buses are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_1 = barI_12 = cfrac1tau_12^2(y_12 + y_texts12) barV_1 -alpha_12^*y_12 barV_2 \n barI_2 = barI_21 + barI_23 + barI_textsh2 = -alpha_12y_12 barV_1 + (y_12 + y_texts12) barV_2 +\n cfrac1tau_23^2(y_23 + y_texts23) barV_2 -alpha_23^*y_23 barV_3 + y_textsh2 barV_2 \n barI_3 = barI_32 = -alpha_23y_23 barV_2 + (y_23 + y_texts23) barV_3\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The system of equations can be written in the matrix form:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_1 barI_2 barI_3\n endbmatrix =\n beginbmatrix\n cfrac1tau_12^2(y_12 + y_texts12) -alpha_12^*y_12 0 \n -alpha_12y_12 y_12 + y_texts12 + cfrac1tau_23^2(y_23 + y_texts23) + y_textsh2 -alpha_23^*y_23 \n 0 -alpha_23y_23 y_23 + y_texts23\n endbmatrix\n beginbmatrix\n barV_1 barV_2 barV_3\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This system of equations can be generalized to accommodate the scenario where the set mathcalN comprises n buses:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" mathbf bar I = mathbfY mathbf bar V","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where mathbf bar V in mathbbC^n is the vector of bus complex voltages, and mathbf bar I in mathbbC^n is the vector of complex current injections at buses. The matrix mathbfY = mathbfG + textjmathbfB in mathbbC^n times n is the bus or nodal admittance matrix, with elements:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"the diagonal elements, where i in mathcalN, are equal to:\nY_ii = G_ii + textjB_ii = y_textshi +\nsumlimits_e in mathcalE e(1) = i cfrac1tau_ij^2(y_ij + y_textsij) + sumlimits_e in mathcalE e(2) = i (y_ji + y_textsji)\nthe non-diagonal elements, where i = e(1) j = e(2) e in mathcalE, are equal to:\n beginaligned\n Y_ij = G_ij + textjB_ij = -alpha_ij^*y_ij 4pt\n Y_ji = G_ji + textjB_ji = -alpha_ijy_ij\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When a branch is not incident (or adjacent) to a bus the corresponding element in the nodal admittance matrix mathbfY is equal to zero. The nodal admittance matrix mathbfY is sparse (i.e., a small number of elements are non-zeros) for real-world power systems. Although it is often assumed that the matrix mathbfY is symmetrical, it is not a general case. For example, in the presence of phase shifting transformers the matrix mathbfY is not symmetric [7, Sec. 9.6]. JuliaGrid stores both the matrix mathbfY and its transpose mathbfY^T in the ac field of the PowerSystem type:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐘 = system.model.ac.nodalMatrix\n𝐘ᵀ = system.model.ac.nodalMatrixTranspose","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BusInjectionsTutorials","page":"Power System Model","title":"Bus Injections","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"From the previous analysis, we can determine the complex current injection at each bus as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" barI_i = sumlimits_j = 1^n Y_ij barV_j i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Furthermore, the calculation of active and reactive power injection at each bus is expressed by the following equation:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_i = P_i + textjQ_i = barV_i sumlimits_j = 1^n Y_ij^* barV_j^* i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Positive values of active or reactive powers, P_i 0 or Q_i 0, indicate that the bus is supplying power into the power system. Conversely, negative values, P_i 0 or Q_i 0, suggest that the bus is drawing active or reactive power from the power system.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BusShuntElementTutorials","page":"Power System Model","title":"Bus Shunt Element","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Based on the previous analysis, we can determine the active and reactive power at the shunt element of each bus using the following equation:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textshi = P_textshi + textjQ_textshi = barV_ibarI_textshi^* = y_textshi^*V_i^2 i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The positive active power value P_textshi 0 indicates that the shunt element is consuming active power. In terms of power flow, this signifies that active power flows from bus i in mathcalN towards the ground. A negative reactive power value Q_textshi 0 suggests that the shunt element is injecting reactive power into the power system. This implies that the direction of reactive power is from the ground to bus i in mathcalN, illustrating the capacitive nature of the shunt component. Conversely, if Q_textshi 0, it indicates an inductive characteristic, implying that the shunt component is absorbing reactive power.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCModelTutorials","page":"Power System Model","title":"DC Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The DC model is obtained by linearization of the nonlinear model, and it provides an approximate solution. In the typical operating conditions, the difference of bus voltage angles between adjacent buses (ij) in mathcalE is very small theta_i-theta_j approx 0, which implies cos (theta_i-theta_j)approx 1 and sin (theta_i-theta_j) approx theta_i-theta_j. Further, all bus voltage magnitudes are V_i approx 1, i in mathcalN, and all branch shunt admittances and branch resistances can be neglected. This implies that the DC model ignores the reactive powers and transmission losses and takes into account only the active powers.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Therefore, the DC power flow takes only bus voltage angles bm Theta in mathbbR^n as variables. To create vectors and matrices related to DC or linear analyses, JuliaGrid uses the function dcModel!:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCBranchNetworkEquationsTutorials","page":"Power System Model","title":"Branch Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"According to the above assumptions, we start from the Unified Branch Model:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_ij barI_ji\n endbmatrix = cfrac1textjx_ij\n beginbmatrix\n cfrac1tau_ij^2 -alpha_ij^*\n -alpha_ij 1\n endbmatrix\n beginbmatrix\n barV_i barV_j\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where barV_i = texte^textjtheta_i and barV_j = texte^textjtheta_j. Further, we have:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_ij = cfrac1textjx_ij leftcfrac1tau_ij^2 texte^textjtheta_i -\n cfrac1tau_ijtexte^textj(phi_ij + theta_j) right \n barI_ji = cfrac1textjx_ij left-cfrac1tau_ijtexte^textj(theta_i - phi_ij) + texte^textjtheta_j right\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power flows are derived as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_ij = RebarV_ibarI_ij^* =\n Re lefttextjcfrac1x_ij\n leftcfrac1tau_ij^2 - cfrac1tau_ije^textj(theta_i - theta_j - phi_ij) right right \n P_ji = RebarV_jbarI_ji^* =\n Re lefttextjcfrac1x_ij\n left1-cfrac1tau_ije^textj(-theta_i +theta_j + phi_ij) right right\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The real components are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_ij =cfrac1tau_ijx_ij sin(theta_i -theta_j-phi_ij) approx cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij) \n P_ji =cfrac1tau_ijx_ij sin(theta_j -theta_i+phi_ij) approx -cfrac1tau_ij x_ij (theta_i - theta_j-phi_ij)\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where 1(tau_ij x_ij) represents the branch admittance in the DC framework. To recall, the PowerSystem type stores the reactances as vector mathbfx = x_ij in the variable:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐱 = system.branch.parameter.reactance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Furthermore, the computed branch admittances in the DC framework are stored in the vector mathbfy = 1(tau_ij x_ij):","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲 = system.model.dc.admittance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can conclude that P_ij=-P_ji holds. With the DC model, the linear network equations relate active powers to bus voltage angles, versus complex currents to complex bus voltages in the AC model [8]. Consequently, analogous to the Branch Network Equations we can write:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_ij P_ji\n endbmatrix = cfrac1tau_ijx_ij\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_i theta_j\n endbmatrix + cfracphi_ijtau_ijx_ij\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCNodalNetworkEquationsTutorials","page":"Power System Model","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As before, let us consider an illustrative example from our case study, depicted in Figure 3. This example provides a smooth transition to the general case, demonstrating a system with three buses represented as mathcalN = 1 2 3 and two branches mathcalE = (1 2) (2 3), where bus 2 is incident to the shunt element with admittance g_textsh2.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 3: The example of the system with three buses and two branches.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Each branch in the DC framework is described with a system of equations as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_12 P_21\n endbmatrix = cfrac1tau_12x_12\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_1 theta_2\n endbmatrix + cfracphi_12tau_12x_12\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_23 P_32\n endbmatrix = cfrac1tau_23x_23\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_2 theta_3\n endbmatrix + cfracphi_23tau_23x_23\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power injections at buses are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_1 = P_12 =cfrac1tau_12x_12 theta_1 - cfrac1tau_12x_12 theta_2 - cfracphi_12tau_12x_12 \n P_2 = P_21 + P_23 + P_textsh2 = -cfrac1tau_12x_12 theta_1 + cfrac1tau_12x_12 theta_2 + cfracphi_12tau_12x_12 +\n cfrac1tau_23x_23 theta_2 - cfrac1tau_23x_23 theta_3 - cfracphi_23tau_23x_23 + g_textsh2 \n P_3 = P_32 = -cfrac1tau_23x_23 theta_2 +cfrac1tau_23x_23 theta_3 + cfracphi_23tau_23x_23\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where the active power injected by the shunt element at the bus 2 is equal to:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" P_textsh2 = RebarV_2barI_textsh2^* = RebarV_2y_textsh2^*barV_2^* = V_2^2 g_textsh2 = g_textsh2","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The system of equations can be written in the matrix form:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_1 P_2 P_3\n endbmatrix =\n beginbmatrix\n cfrac1tau_12x_12 - cfrac1tau_12x_12 0 \n -cfrac1tau_12x_12 cfrac1tau_12x_12 + cfrac1tau_23x_23 -cfrac1tau_23x_23 \n 0 -cfrac1tau_23x_23 cfrac1tau_23x_23\n endbmatrix\n beginbmatrix\n theta_1 theta_2 theta_3\n endbmatrix +\n beginbmatrix\n - cfracphi_12tau_12x_12 cfracphi_12tau_12x_12 - cfracphi_23tau_23x_23 cfracphi_23tau_23x_23\n endbmatrix +\n beginbmatrix\n 0 g_textsh2 0\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This system of equations can be generalized to accommodate the scenario where the set mathcalN comprises n buses:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" mathbf P = mathbfB bm Theta + mathbfP_texttr + mathbfP_textsh","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where bm Theta in mathbbR^n is the vector of bus voltage angles.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbf P in mathbbR^n contains active power injections at buses caused by generators and demands. In JuliaGrid, the vector can be recovered using a command:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏 = system.bus.supply.active - system.bus.demand.active","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbfP_texttr in mathbbR^n represents active powers related to the non-zero shift angle of transformers. This vector is stored in the dc field, and we can access it using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏ₜᵣ = system.model.dc.shiftPower","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbfP_textsh in mathbbR^n represents active powers consumed by shunt elements. We can access this vector using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏ₛₕ = system.bus.shunt.conductance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The bus or nodal matrix in the DC framework is given as mathbfB in mathbbR^n times n, with elements:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"the diagonal elements, where i in mathcalN, are equal to:\nB_ii = sumlimits_e in mathcalE i in e cfrac1tau_ijx_ij\nthe non-diagonal elements, where i = e(1) j = e(2) e in mathcalE, are equal to:\n beginaligned\n B_ij = -cfrac1tau_ijx_ij 3pt\n B_ji = -cfrac1tau_ijx_ij\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The sparse nodal matrix mathbfB is stored in the dc field, and we can access it using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐁 = system.model.dc.nodalMatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCBusInjectionTutorials","page":"Power System Model","title":"Bus Injection","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"From the previous analysis, the calculation of active power injection at each bus is expressed by:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" P_i = sum_j = 1^n B_ij theta_j + P_texttri + P_textshi i in mathcalN","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowManual","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similar to AC Optimal Power Flow, JuliaGrid utilizes the JuMP package to construct optimal power flow models, enabling users to manipulate these models using the standard functions provided by JuMP. JuliaGrid supports popular solvers mentioned in the JuMP documentation to solve the optimization problem.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To perform the DC optimal power flow, we first need to have the PowerSystem type that has been created with the DC model. After that, create the DCOptimalPowerFlow type to establish the DC optimal power flow framework using the function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"dcOptimalPowerFlow.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To solve the DC optimal power flow problem and acquire generator active power outputs and bus voltage angles, make use of the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"solve!.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution for DC optimal power flow, JuliaGrid offers a post-processing analysis function to compute powers associated with buses and branches:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses, branches, or generators.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowModelManual","page":"DC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To set up the DC optimal power flow, we begin by creating the model. To illustrate this, consider the following:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, HiGHS\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05)\n\n@branch(minDiffAngle = -3.1, maxDiffAngle = 3.1, minFromBus = -0.12, maxFromBus = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.6, maxActive = 0.8)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.1, maxActive = 0.3)\naddGenerator!(system; label = \"Generator 3\", bus = \"Bus 2\", active = 0.2, maxActive = 0.4)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [8.0 11.0; 14.0 17.0])\ncost!(system; label = \"Generator 3\", active = 1, piecewise = [6.8 12.3; 8.7 16.8; 11.2 19.8])\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, the dcOptimalPowerFlow function is utilized to formulate the DC optimal power flow problem:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimizationVariablesManual","page":"DC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In DC optimal power flow, generator active power outputs are linear functions of bus voltage angles. Thus, the model's variables include generator active power outputs and bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.all_variables(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is important to highlight that when dealing with linear piecewise cost functions comprising multiple segments, as exemplified in the case of Generator 3, JuliaGrid automatically generates helper optimization variables, such as actwise[3], and formulates a set of linear constraints to appropriately handle these cost functions.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"However, in instances where a linear piecewise cost function consists of only a single segment, as demonstrated by Generator 2, the function is modelled as a standard linear function, eliminating the necessity for additional helper optimization variables.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Please note that JuliaGrid keeps references to all variables categorized into three fields:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.variable))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Variable-Names","page":"DC Optimal Power Flow","title":"Variable Names","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the option to define custom variable names for printing and writing equations, which can help present them in a more compact form. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer; active = \"P\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-Variables","page":"DC Optimal Power Flow","title":"Add Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The user has the ability to easily add new variables to the defined DC optimal power flow model by using the @variable macro from the JuMP package:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.@variable(analysis.method.jump, newVariable)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We can verify that the new variable is included in the defined model by using the function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Delete-Variables","page":"DC Optimal Power Flow","title":"Delete Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To delete a variable, the delete function from the JuMP package can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After deletion, the variable is no longer part of the model:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCConstraintFunctionsManual","page":"DC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuliGrid keeps track of all the references to internally formed constraints in the constraint field of the DCOptimalPowerFlow type. These constraints are divided into six fields:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.constraint))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nWe suggest that readers refer to the tutorial on DC Optimal Power Flow for insights into the implementation.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Slack-Bus-Constraint","page":"DC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The slack field contains a reference to the equality constraint associated with the fixed bus voltage angle value of the slack bus. This constraint is set within the addBus! function using the angle keyword:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the flexibility to modify this constraint by changing which bus serves as the slack bus and by adjusting the value of the bus angle. This can be achieved using the updateBus! function, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", angle = -0.1)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated slack constraint can be inspected as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Bus-Active-Power-Balance-Constraints","page":"DC Optimal Power Flow","title":"Bus Active Power Balance Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The balance field contains references to the equality constraints associated with the active power balance equations defined for each bus. The constant terms in these equations are determined by the active and conductance keywords within the addBus! function. Additionally, if there are phase shift transformers in the system, the constant terms can also be affected by the shiftAngle keyword within the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"During the execution of functions that add or update power system components, these constraints are automatically adjusted to reflect the current configuration of the power system, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 3\", active = 0.1)\nupdateGenerator!(system, analysis; label = \"Generator 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power balance constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Bus-Voltage-Angle-Difference-Constraints","page":"DC Optimal Power Flow","title":"Bus Voltage Angle Difference Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The voltage field contains references to the inequality constraints associated with the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch. These values are specified using the minDiffAngle and maxDiffAngle keywords within the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nPlease note that if the limit constraints are set to minDiffAngle = -2π and maxDiffAngle = 2π for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, by employing the updateBranch! function, we have the ability to modify these constraints as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", minDiffAngle = -1.7, maxDiffAngle = 1.7)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of voltage angle difference constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Branch-Active-Power-Flow-Constraints","page":"DC Optimal Power Flow","title":"Branch Active Power Flow Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The flow field refers to the inequality constraints associated with active power flow limits at the from-bus end of each branch. These limits are set using the minFromBus and maxFromBus keywords in the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nIf the branch flow limits are set to minFromBus = 0.0 and maxFromBus = 0.0 for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By employing the updateBranch! function, we have the ability to modify these specific constraints, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", status = 0)\nupdateBranch!(system, analysis; label = \"Branch 2\", reactance = 0.03, maxFromBus = 0.14)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power flow constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Generator-Active-Power-Capability-Constraints","page":"DC Optimal Power Flow","title":"Generator Active Power Capability Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The capability field contains references to the inequality constraints associated with the minimum and maximum active power outputs of the generators. These limits are specified using the minActive and maxActive keywords within the addGenerator! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As demonstrated, the active power output of Generator 2 is currently fixed at zero due to the earlier action of setting this generator out-of-service. Let us adjust this specific constraint using the updateGenerator! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", status = 1, maxActive = 0.5)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power capability constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is important to note that bringing back Generator 2 into service will also have an impact on the balance constraint, which will once again be influenced by the generator's output.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Piecewise-Constraints","page":"DC Optimal Power Flow","title":"Active Power Piecewise Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the context of active power modelling, the piecewise field serves as a reference to the inequality constraints related to linear piecewise cost functions. These constraints are created using the cost! function with active = 1 specified when dealing with linear piecewise cost functions comprising multiple segments. JuliaGrid takes care of establishing the appropriate inequality constraints for each segment of the linear piecewise cost:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.piecewise.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is worth noting that these constraints can also be automatically updated using the cost! function, and readers can find more details in the section about the objective function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-Constraints","page":"DC Optimal Power Flow","title":"Add Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can effortlessly introduce additional constraints into the defined DC optimal power flow model by utilizing the addBranch! or addGenerator! functions. Specifically, if a user wishes to include a new branch or generator in an already defined PowerSystem and DCOptimalPowerFlow type:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"addBranch!(system, analysis; label = \"Branch 4\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\naddGenerator!(system, analysis; label = \"Generator 4\", bus = \"Bus 1\", maxActive = 0.2)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As a result, the flow and capability constraints will be adjusted as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)\nprint(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-User-Defined-Constraints","page":"DC Optimal Power Flow","title":"Add User-Defined Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users also have the option to include their custom constraints within the established DC optimal power flow model by employing the @constraint macro. For example, the addition of a new constraint can be achieved as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.@constraint(analysis.method.jump, 0.0 <= analysis.method.variable.active[4] <= 0.3)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Delete-Constraints","page":"DC Optimal Power Flow","title":"Delete Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To delete a constraint, users can make use of the delete function from the JuMP package. When handling constraints that have been internally created, users can refer to the constraint references stored in the constraint field of the DCOptimalPowerFlow type.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"For example, if the intention is to eliminate constraints related to the capability of Generator 4, the following code snippet can be employed:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, analysis.method.constraint.capability.active[4])\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nIn the event that a user deletes a constraint and subsequently executes a function that updates bus, branch, or generator parameters, and if the deleted constraint is affected by these functions, JuliaGrid will automatically reinstate that constraint. Users should exercise caution when deleting constraints, as this action is considered potentially harmful since it operates independently of power system data.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCObjectiveFunctionManual","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The objective function of the DC optimal power flow is constructed using polynomial and linear piecewise cost functions of the generators, which are defined using the cost! functions. It is important to note that only polynomial cost functions up to the second degree are included in the objective. If there are polynomials of higher degrees, JuliaGrid will exclude them from the objective function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the provided example, the objective function that needs to be minimized to obtain the optimal values of the active power outputs of the generators and the bus voltage angles is as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, JuliaGrid stores the objective function in a separate variable, allowing users to access it by referencing the variable analysis.objective.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Update-Objective-Function","page":"DC Optimal Power Flow","title":"Update Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By utilizing the cost! functions, users have the flexibility to modify the objective function by adjusting polynomial or linear piecewise cost coefficients or by changing the type of polynomial or linear piecewise function employed. For instance, consider Generator 3, which incorporates a piecewise cost structure with two segments. Now, we can define a polynomial function for this generator and activate it by specifying the keyword active = 2 as shown:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"cost!(system, analysis; label = \"Generator 3\", active = 2, polynomial = [853.4; 257; 40])","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"This results in the updated objective function, which can be observed as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.objective","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#User-Defined-Objective-Function","page":"DC Optimal Power Flow","title":"User-Defined Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can modify the objective function using the set_objective_function function from the JuMP package. This operation is considered destructive because it is independent of power system data; however, in certain scenarios, it may be more straightforward than using the cost! function for updates. Moreover, using this methodology, users can combine a defined function with a newly defined expression. Here is an example of how it can be achieved:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"expr = 100.2 * analysis.method.variable.active[1] * analysis.method.variable.active[1] + 123\nJuMP.set_objective_function(analysis.method.jump, analysis.method.objective - expr)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We can now observe the updated objective function as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#SetupStartingPrimalValuesManual","page":"DC Optimal Power Flow","title":"Setup Starting Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In JuliaGrid, the assignment of starting primal and dual values for optimization variables takes place when the solve! function is executed.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Starting-Primal-Values","page":"DC Optimal Power Flow","title":"Starting Primal Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Starting primal values are determined based on the generator and voltage fields within the DCOptimalPowerFlow type. By default, these values are initially established using the active power outputs of the generators and the initial bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the flexibility to adjust these values according to their specifications, which will then be used as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Using-DC-Power-Flow","page":"DC Optimal Power Flow","title":"Using DC Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this perspective, users have the capability to conduct the DC power flow analysis and leverage the resulting solution to configure starting primal values. Here is an illustration of how this can be achieved:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"flow = dcPowerFlow(system)\nsolve!(system, flow)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution, we can calculate the active power outputs of the generators and utilize the bus voltage angles to set the starting values. In this case, the generator and voltage fields of the DCOptimalPowerFlow type can be employed to store the new starting values:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"for (key, idx) in system.generator.label\n analysis.power.generator.active[idx] = generatorPower(system, flow; label = key)\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.angle[i] = flow.voltage.angle[i]\nend","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Starting-Dual-Values","page":"DC Optimal Power Flow","title":"Starting Dual Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Dual variables, often referred to as Lagrange multipliers or Kuhn-Tucker multipliers, represent the shadow prices or marginal costs associated with constraints. The assignment of initial dual values occurs when the solve! function is executed. Initially, the starting dual values are unknown, but users can access and manually set them. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.dual.balance.active[1] = 0.4\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowSolutionManual","page":"DC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To establish the DC optimal power flow problem, we can utilize the dcOptimalPowerFlow function. After setting up the problem, we can use the solve! function to compute the optimal values for the active power outputs of the generators and the bus voltage angles. Also, to turn off the solver output within the REPL, we use the set_silent function before calling solve! function. Here is an example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By executing this function, we will obtain the solution with the optimal values for the active power outputs of the generators and the bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Objective-Value","page":"DC Optimal Power Flow","title":"Objective Value","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To obtain the objective value of the optimal power flow solution, we can use the objective_value function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_value(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Dual-Variables","page":"DC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The values of the dual variables are stored in the dual field of the DCOptimalPowerFlow type. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.dual.balance.active[1]","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Print-Results-in-the-REPL","page":"DC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can utilize the functions printBusData and printGeneratorData to display results. Additionally, the functions listed in the Print Constraint Data section allow users to print constraint data related to buses, branches, or generators in the desired units. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"@power(MW, MVAr, pu)\nprintBusConstraint(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, users can easily customize the print results for specific constraint, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"printBusConstraint(system, analysis; label = \"Bus 1\", header = true)\nprintBusConstraint(system, analysis; label = \"Bus 2\", footer = true)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Save-Results-to-a-File","page":"DC Optimal Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusConstraint(system, analysis, file)\nend","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Save-Results-to-a-CSV-File","page":"DC Optimal Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusConstraint(system, analysis, io; style = false)\nCSV.write(\"constraint.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Primal-and-Dual-Warm-Start","page":"DC Optimal Power Flow","title":"Primal and Dual Warm Start","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Utilizing the DCOptimalPowerFlow type and proceeding directly to the solver offers the advantage of a \"warm start\". In this scenario, the starting primal and dual values for the subsequent solving step correspond to the solution obtained from the previous step.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Primal-Variables","page":"DC Optimal Power Flow","title":"Primal Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the previous example, the following solution was obtained, representing the values of the primal variables:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Dual-Variables-2","page":"DC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We also obtained all dual values. Here, we list only the dual variables for one type of constraint as an example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.dual.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Modify-Optimal-Power-Flow","page":"DC Optimal Power Flow","title":"Modify Optimal Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Now, let us introduce changes to the power system from the previous example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", maxActive = 0.08)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, we want to solve this modified optimal power flow problem. If we use solve! at this point, the primal and dual starting values will be set to the previously obtained values:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"solve!(system, analysis)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As a result, we obtain a new solution:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Reset-Primal-and-Dual-Values","page":"DC Optimal Power Flow","title":"Reset Primal and Dual Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users retain the flexibility to reset these initial primal values to their default configurations at any juncture. This can be accomplished by utilizing the active power outputs of the generators and the initial bus voltage angles extracted from the PowerSystem type, employing the startingPrimal! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"startingPrimal!(system, analysis)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The primal starting values will now be identical to those that would be obtained if the dcOptimalPowerFlow function were executed after all the updates have been applied.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Using the startingDual! function, users can clear all dual variable values, resetting them to their default state:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"startingDual!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerAnalysisManual","page":"DC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution from the DC optimal power flow, we can calculate powers related to buses and branches using the power! function. For instance, let us consider the power system for which we obtained the DC optimal power flow solution:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid, JuMP # hide\nusing HiGHS\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, minFromBus = -0.12, maxFromBus = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, maxActive = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, maxActive = 0.2)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8])\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Now we can calculate the active powers using the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Finally, to display the active power injections and from-bus active power flows, we can use the following code:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.power.from.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nTo better understand the powers associated with buses and branches that are calculated by the power! function, we suggest referring to the tutorials on DC Optimal Power Flow.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Print-Results-in-the-REPL-2","page":"DC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus data with the desired units, users can use the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nprintBusData(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Injection","page":"DC Optimal Power Flow","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = injectionPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Injection-from-Generators","page":"DC Optimal Power Flow","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = supplyPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Flow","page":"DC Optimal Power Flow","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = fromPower(system, analysis; label = \"Branch 2\")\nactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/powerSystemModel/#PowerSystemModelManual","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid supports the type PowerSystem to preserve power system data, with the following fields: bus, branch, generator, base, and model. The bus, branch, and generator fields hold data related to buses, branches, and generators, respectively. The base field stores base values for power and voltages, with the default being three-phase power measured in volt-amperes for the base power and line-to-line voltages measured in volts for base voltages. Within the model field, the ac and dc subfields store vectors and matrices pertinent to the power system's topology and parameters, and these are utilized in either the AC or DC framework.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The type PowerSystem can be created using a function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid supports three modes for populating the PowerSystem type: using built-in functions, using HDF5 file format, and using Matpower case files.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is recommended to use the HDF5 format for large-scale systems. To facilitate this, JuliaGrid has the function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"savePowerSystem.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Upon creation of the PowerSystem type, users can generate vectors and matrices based on the power system topology and parameters using the following functions:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"acModel!,\ndcModel!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once the PowerSystem type is created, users can add buses, branches, generators, or manage costs associated with the output powers of the generators, using the following functions:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!,\naddBranch!,\naddGenerator!,\ncost!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid also provides macros @bus, @branch, and @generator to define templates that aid in creating buses, branches, and generators. These templates help avoid entering the same parameters repeatedly.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, it is feasible to modify the parameters of buses, branches, and generators. When these functions are executed, all relevant fields within the PowerSystem type will be automatically updated, encompassing the ac and dc fields as well. These functions include:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBus!,\nupdateBranch!,\nupdateGenerator!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nThe functions addBranch!, addGenerator!, updateBus!, updateBranch!, updateGenerator!, and cost! serve a dual purpose. While their primary function is to modify the PowerSystem type, they are also designed to accept various analysis models like AC or DC power flow models. When feasible, these functions not only modify the PowerSystem type but also adapt the analysis model, often resulting in improved computational efficiency. Detailed instructions on utilizing this feature can be found in dedicated manuals for specific analyses.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#BuildModelManual","page":"Power System Model","title":"Build Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The powerSystem function generates the PowerSystem type and requires a string-formatted path to either Matpower cases or HDF5 files as input. Alternatively, the PowerSystem can be created without any initial data by initializing it as empty, allowing the user to construct the power system from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Matpower-File","page":"Power System Model","title":"Matpower File","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For example, to create the PowerSystem type using the Matpower case file for the IEEE 14-bus test case, which is named case14.m and located in the folder C:\\matpower, the following Julia code can be used:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem(\"C:/matpower/case14.m\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#HDF5-File","page":"Power System Model","title":"HDF5 File","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In order to use the HDF5 file as input to create the PowerSystem type, it is necessary to have saved the data using the savePowerSystem function beforehand. As an example, let us say we saved the power system as case14.h5 in the directory C:\\hdf5. In this case, the following Julia code can be used to construct the PowerSystem type:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem(\"C:/hdf5/case14.h5\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIt is recommended to load the power system from the HDF5 file to reduce the loading time.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Model-from-Scratch","page":"Power System Model","title":"Model from Scratch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Alternatively, the model can be built from scratch using built-in functions, for example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, base = 345e3)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, base = 345e3)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Internal-Unit-System","page":"Power System Model","title":"Internal Unit System","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The PowerSystem type stores all electrical quantities in per-units and radians, except for the base values of power and voltages. The base power value is expressed in volt-amperes, while the base voltages are given in volts.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Change-Base-Unit-Prefixes","page":"Power System Model","title":"Change Base Unit Prefixes","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The user can retrieve the base power and base voltage values along with their respective units:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.power.value, system.base.power.unit\nsystem.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"By using the @base macro, users can change the prefixes of the base units. For instance, if users wish to convert base power and base voltage values to megavolt-amperes (MVA) and kilovolts (kV) respectively, they can execute the following macro:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@base(system, MVA, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After executing the macro, the base power and voltage values and their units will be modified accordingly:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.power.value, system.base.power.unit\nsystem.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#SaveModelManual","page":"Power System Model","title":"Save Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once the PowerSystem type has been created using one of the methods outlined in Build Model, the data can be stored in the HDF5 file by using the savePowerSystem function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"savePowerSystem(system; path = \"C:/matpower/case14.h5\", reference = \"IEEE 14-bus test case\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"All electrical quantities saved in the HDF5 file are in per-units and radians, except for base values for power and voltages, which are given in volt-amperes and volts. Note that even if the user modifies the base units using the @base macro, the units will still be saved with the default settings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddBusManual","page":"Power System Model","title":"Add Bus","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The buses can be added both to the loaded power system, or to the one created from scratch. As an illustration, we can initiate the PowerSystem type and then incorporate two buses by utilizing the addBus! function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, base = 345e3)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.034907, base = 345e3)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this case, we have created two buses where the active power demanded by the consumer at Bus 1 is specified in per-units, which are the same units used to store electrical quantities:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.demand.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is worth noting that the base keyword is used to specify the base voltages, and its default input unit is in volts (V):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Also, we have defined the bus voltage angle in radians for Bus 2 as its initial value:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.voltage.angle","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nWe recommend reading the documentation for the addBus! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Typically, all keywords associated with electrical quantities are expected to be provided in per-units (pu) and radians (rad) by default, with the exception of base voltages, which should be specified in volts (V). However, users can choose to use different units than the default per-units and radians or modify the prefix of the base voltage unit by using macros such as the following:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\n@power(MW, MVAr, pu)\n@voltage(pu, deg, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This practical example showcases the customization approach. For keywords tied to active powers, the unit is set as megawatts (MW), while reactive powers employ megavolt-amperes reactive (MVAr). Apparent power, on the other hand, employs per-units (pu). As for keywords concerning voltage magnitude, per-units (pu) remain the choice, but voltage angle mandates degrees (deg). Lastly, the input unit for base voltage is elected to be kilovolts (kV).","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now we can create identical two buses as before using new system of units as follows:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 10.0, base = 345.0)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -2.0, base = 345.0)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As can be observed, electrical quantities will continue to be stored in per-units and radians format:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[system.bus.demand.active system.bus.voltage.angle]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The base voltage values will still be stored in volts (V) since we only changed the input unit prefix, and did not modify the internal unit prefix, as shown below:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To modify the internal unit prefix, the following macro can be used:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@base(system, VA, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After executing this macro, the base voltage values will be stored in kilovolts (kV):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddBranchManual","page":"Power System Model","title":"Add Branch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch connecting two buses can be added once those buses are defined, and from and to keywords must correspond to labels of those buses. For example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Here, we created the branch from Bus 1 to Bus 2 with following parameter:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is recommended to consult the documentation for the addBranch! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-2","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To use units other than per-units (pu) and radians (rad), macros can be employed to change the input units. For example, if there is a need to use ohms (Ω), the macros below can be employed:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@parameter(Ω, pu)\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 22.8528)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Still, all electrical quantities are stored in per-units, and the same branch as before is created:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is important to note that, when working with impedance and admittance values in ohms (Ω) and siemens (S) that are related to a transformer, the assignment must be based on the primary side of the transformer.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddGeneratorManual","page":"Power System Model","title":"Add Generator","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The generator connected to a bus can be added once the bus is defined. Each generator must have a unique label, and the bus keyword should correspond to the unique label of the bus it is connected to. For instance:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 2\", active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the above code, we add the generator to the Bus 2, with active and reactive power outputs set to:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.output.active, system.generator.output.reactive","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similar to buses and branches, the input units can be changed to units other than per-units using different macros.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is recommended to refer to the documentation for the addGenerator! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddTemplatesManual","page":"Power System Model","title":"Add Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The functions addBus!, addBranch!, and addGenerator! are used to add bus, branch, and generator to the power system, respectively. If certain keywords are not specified, default values are assigned to some parameters.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Default-Keyword-Values","page":"Power System Model","title":"Default Keyword Values","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Regarding the addBus! function, the bus type is automatically configured as a demand bus with type = 1. The initial bus voltage magnitude is set to magnitude = 1.0 per-unit, while the base voltage is established as base = 138e3 volts. Additionally, the minimum and maximum bus voltage magnitudes are set to minMagnitude = 0.9 per-unit and maxMagnitude = 1.1 per-unit, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Transitioning to the addBranch! function, the default operational status is status = 1, indicating that the branch is in-service. The off-nominal turns ratio for the transformer is specified as turnsRatio = 1.0, and the phase shift angle is set to shiftAngle = 0.0, collectively defining the line configuration with these standard settings. The flow rating is also configured as type = 1. Moreover, the minimum and maximum voltage angle differences between the from-bus and to-bus ends are set to minDiffAngle = -2pi and maxDiffAngle = 2pi, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, the addGenerator! function designates an operational generator by employing status = 1, and it sets magnitude = 1.0 per-unit, denoting the desired voltage magnitude setpoint.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The remaining parameters are initialized with default values of zero.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Change-Default-Keyword-Values","page":"Power System Model","title":"Change Default Keyword Values","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In JuliaGrid, users have the flexibility to adjust default values and assign customized values using the @bus, @branch, and @generator macros. These macros create bus, branch, and generator templates that are used every time the addBus!, addBranch!, and addGenerator! functions are called. For instance, the code block shows an example of creating bus, branch, and generator templates with customized default values:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\n@bus(type = 2, active = 0.1)\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\n\n@branch(reactance = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\")\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.06)\n\n@generator(magnitude = 1.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.6)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This code example involves two uses of the addBus! and addBranch! functions. In the first use, the functions rely on the default values set by the templates created with the @bus and @branch macros. In contrast, the second use passes specific values that match the keywords used in the templates. As a result, the templates are ignored:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.layout.type\nsystem.bus.demand.active\nsystem.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the given example, the @generator macro is utilized instead of repeatedly specifying the magnitude keyword in the addGenerator! function. This macro creates a generator template with a default value for magnitude, which is automatically applied every time the addGenerator! function is called. Therefore, it eliminates the requirement to set the magnitude value for each individual generator:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.voltage.magnitude","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-3","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Templates can also be defined using a custom unit system, for example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\n@power(MW, MVAr, MVA)\n@bus(active = 100, reactive = 200)\naddBus!(system; label = \"Bus 1\")\n\n@power(pu, pu, pu)\naddBus!(system; label = \"Bus 2\", active = 0.5)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, we create the bus template and one bus using SI power units, and then we switch to per-units and add the second bus. It is important to note that once the template is defined in any unit system, it remains valid regardless of subsequent unit system changes. The resulting power values are:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.demand.active\nsystem.bus.demand.reactive","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Thus, JuliaGrid automatically tracks the unit system used to create templates and provides the appropriate conversion to per-units and radians. Even if the user switches to a different unit system later on, the previously defined template will still be valid.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Multiple-Templates","page":"Power System Model","title":"Multiple Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the case of calling the @bus, @branch, or @generator macros multiple times, the provided keywords and values will be combined into a single template for the corresponding component (bus, branch, or generator), which will be used for generating the component.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Reset-Templates","page":"Power System Model","title":"Reset Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To reset the bus, branch, and generator templates to their default settings, users can utilize the following macros:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@default(bus)\n@default(branch)\n@default(generator)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Additionally, users can reset all templates using the macro:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@default(template)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#LabelsManual","page":"Power System Model","title":"Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we have shown, JuliaGrid mandates a distinctive label for every bus, branch, or generator. These labels are stored in ordered dictionaries, functioning as pairs of strings and integers. The string signifies the exclusive label for the specific component, whereas the integer maintains an internal numbering of buses, branches, or generators.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nString labels improve readability, but in larger models, the overhead from using strings can become substantial. To reduce memory usage, users can configure ordered dictionaries to accept and store integers as labels:@labels(Integer)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Integer-Based-Labeling","page":"Power System Model","title":"Integer-Based Labeling","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us take a look at the following illustration:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.1)\naddBus!(system; label = 2, type = 1, angle = -0.2)\n\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.12)\n\naddGenerator!(system; label = 1, bus = 2, active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, we use the macro @labels to specify that labels will be stored as integers. It is essential to run this macro; otherwise, even if integers are used in subsequent functions, they will be stored as strings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Here, two buses are created with labels 1 and 2. A branch connects these two buses, assigned a unique label of 1. Finally, a generator is connected to bus 2, with its own label set to 1.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Automated-Labeling","page":"Power System Model","title":"Automated Labeling","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Users also possess the option to omit the label keyword, allowing JuliaGrid to independently allocate unique labels for buses, branches, or generators. In such instances, JuliaGrid employs an ordered set of incremental integers for labeling components. To illustrate, consider the subsequent example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; type = 3, active = 0.1)\naddBus!(system; type = 1, angle = -0.2)\n\naddBranch!(system; from = 1, to = 2, reactance = 0.12)\n\naddGenerator!(system; bus = 2, active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This example models the same power system as before. In the previous case, we manually assigned labels using incremental integers. Here, we rely on the automatic labeling behavior, but since the macro @labels is not used, the labels will be stored as strings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Automated-Labeling-Using-Templates","page":"Power System Model","title":"Automated Labeling Using Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Additionally, users have the ability to generate labels through templates and employ the symbol ? to insert an incremental set of integers at any location. For instance:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\n@bus(label = \"Bus ? HV\")\naddBus!(system; type = 3, active = 0.1)\naddBus!(system; type = 1, angle = -0.2)\n\n@branch(label = \"Branch ?\")\naddBranch!(system; from = \"Bus 1 HV\", to = \"Bus 2 HV\", reactance = 0.12)\n\n@generator(label = \"Generator ?\")\naddGenerator!(system; bus = \"Bus 2 HV\", active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, two buses are generated and labeled as Bus 1 HV and Bus 2 HV, along with one branch and one generator labeled as Branch 1 and Generator 1, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Retrieving-Labels","page":"Power System Model","title":"Retrieving Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Finally, we will outline how users can retrieve stored labels. Let us consider the following power system creation:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 2\")\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 3\")\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 1\", reactance = 0.8)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\")\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 3\")\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For instance, the bus labels can be accessed using the variable:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.label","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"If the objective is to obtain only labels, users can utilize the following:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"label = collect(keys(system.bus.label))","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This approach can also be extended to branch and generator labels by making use of the variables present within the PowerSystem type, namely system.branch.label or system.generator.label.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, the from and to keywords associated with branches are stored based on internally assigned numerical values linked to bus labels. These values are stored in variables:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[system.branch.layout.from system.branch.layout.to]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To recover the original from and to labels, we can utilize:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[label[system.branch.layout.from] label[system.branch.layout.to]]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, the bus keywords related to generators are saved based on internally assigned numerical values corresponding to bus labels and can be accessed using:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.layout.bus","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To recover the original bus labels, we can utilize:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"label[system.generator.layout.bus]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nJuliaGrid offers the capability to print labels alongside various types of data, such as power system parameters, voltages, powers, currents, or constraints used in optimal power flow analyses. For instance:print(system.branch.label, system.branch.parameter.reactance)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Loading-and-Saving-Labels","page":"Power System Model","title":"Loading and Saving Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When a user loads a power system from a Matpower file, the default behavior is to store labels as strings. However, this can be overridden by using the @labels macro to store labels as integers.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When saving the power system to an HDF5 file, the label type (strings or integers) will match the type chosen during system setup. Likewise, when loading data from an HDF5 file, the label type will be preserved as saved, regardless of what is set by the @labels macro.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#ACDCModelManual","page":"Power System Model","title":"AC and DC Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When we constructed the power system, we can create an AC and/or DC model, which include vectors and matrices related to the power system's topology and parameters. The following code snippet demonstrates this:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", resistance = 0.008, reactance = 0.05)\n\nacModel!(system)\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIn many instances throughout the JuliaGrid documentation, we explicitly mention these functions by their names, although it is not mandatory. If a user begins any of the various AC or DC analyses without having previously established the AC or DC model using the acModel! or dcModel! function, the respective function for setting the analysis will automatically create the AC or DC model.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The nodal matrices are one of the components of both the AC and DC models and are stored in the variables:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix\nsystem.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe AC model is used for performing AC power flow, AC optimal power flow, AC state estimation, or state estimation with PMUs, whereas the DC model is essential for various DC or linear analyses. Consequently, once these models are developed, they can be applied to various types of simulations. We recommend that the reader refers to the tutorial on AC and DC models.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#New-Branch-Triggers-Model-Update","page":"Power System Model","title":"New Branch Triggers Model Update","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can execute the acModel! and dcModel! functions after defining the final number of buses, and each new branch added will trigger an update of the AC and DC matrices and vectors. Here is an example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\nacModel!(system)\ndcModel!(system)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", resistance = 0.008, reactance = 0.05)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For example, the nodal matrix in the DC framework has the same values as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIt is not fully recommended to create AC and DC models before adding a large number of branches if the execution time of functions is important. Instead, triggering updates to the AC and DC models using the addBranch! function is useful for power systems that require the addition of several branches. This update avoids the need to recreate vectors and matrices from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#New-Bus-Triggers-Model-Erasure","page":"Power System Model","title":"New Bus Triggers Model Erasure","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The AC and DC models must be defined once a finite number of buses has been defined, otherwise, adding a new bus will delete them. For example, if we attempt to add a new bus to the PowerSystem type that was previously created, the current AC and DC models will be completely erased:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!(system; label = \"Bus 4\", type = 2)\nsystem.model.ac.nodalMatrix\nsystem.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateBusManual","page":"Power System Model","title":"Update Bus","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once a bus has been added to the PowerSystem type, users have the flexibility to modify all parameters defined within the addBus! function. This means that when the updateBus! function is used, the PowerSystem type within AC and DC models that have been created is updated. This eliminates the need to recreate the AC and DC models from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To illustrate, let us consider the following power system:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, conductance = 0.01)\naddBus!(system; label = \"Bus 2\", type = 2, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\n\nacModel!(system)\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For instance, the nodal matrix in the AC framework has the following form:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now, let us add a shunt element to Bus 2:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBus!(system; label = \"Bus 2\", conductance = 0.4, susceptance = 0.5)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we can observe, executing the function triggers an update of the AC nodal matrix:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateBranchManual","page":"Power System Model","title":"Update Branch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once a branch has been added to the PowerSystem type, users have the flexibility to modify all parameters defined within the addBranch! function. This means that when the updateBranch! function is used, the PowerSystem type within AC and DC models that have been created is updated. This eliminates the need to recreate the AC and DC models from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To illustrate, let us continue with the previous example and modify the parameters of Branch 1 as follows:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBranch!(system; label = \"Branch 1\", resistance = 0.012, reactance = 0.3)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can observe the update in the AC nodal matrix:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Next, let us switch the status of Branch 2 from in-service to out-of-service:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBranch!(system; label = \"Branch 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As before, the updated AC nodal matrix takes the following form:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Drop-Zeros","page":"Power System Model","title":"Drop Zeros","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After the last execution of the updateBranch! function, the nodal matrices will contain zeros, as demonstrated in the code example. If needed, the user can remove these zeros using the dropZeros! function, as shown below:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"dropZeros!(system.model.ac)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is worth mentioning that in simulations conducted with the JuliaGrid package, the precision of the outcomes remains unaffected even if zero entries are retained. However, we recommend users utilize this function instead of dropzeros! from the SuiteSparse package to ensure seamless functioning of all JuliaGrid functionalities.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateGeneratorManual","page":"Power System Model","title":"Update Generator","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Finally, users can update all generator parameters defined within the addGenerator! function using the updateGenerator! function. The execution of this function will affect all variables within the PowerSystem type.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In short, in addition to the generator field, JuliaGrid also retains variables associated with generators within the bus field. As an example, let us examine one of these variables and its values derived from a previous example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.supply.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Next, we will change the active output power of Generator 1:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateGenerator!(system; label = \"Generator 1\", active = 0.9)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we can see, executing the function triggers an update of the observed variable:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.supply.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Hence, this function ensures the adjustment of generator parameters and updates all fields of the PowerSystem type affected by them.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddUpdateCostsManual","page":"Power System Model","title":"Add and Update Costs","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The cost! function is responsible for adding and updating costs associated with the active or reactive power produced by the corresponding generator. These costs are added only if the corresponding generator is defined.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To start, let us create an example of a power system using the following code:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 2\")\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Polynomial-Cost","page":"Power System Model","title":"Polynomial Cost","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us define a quadratic polynomial cost function for the active power produced by the Generator 1:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.0; 500.0; 150.0])","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In essence, what we have accomplished is the establishment of a cost function depicted as f(P_textg1) = 1100 P_textg1^2 + 500 P_textg1 + 150 through the code provided. In general, when constructing a polynomial cost function, the coefficients must be ordered from the highest degree to the lowest.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The default input units are in per-units (pu), with coefficients of the cost function having units of currency/pu²-hr for 1100, currency/pu-hr for 500, and currency/hr for 150. Therefore, the coefficients are stored exactly as entered:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.active.polynomial[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"By setting active = 2 within the function, we express our intent to specify the active power cost using the active key. By using a value of 2, we signify our preference for employing a polynomial cost model for the associated generator. This flexibility is neccessary when we have also previously defined a piecewise linear cost function for the same generator. In such cases, we can set active = 1 to utilize the piecewise linear cost function to represent the cost of the corresponding generators. Thus, we retain the freedom to choose between these two cost functions according to the requirements of our simulation. Additionally, users have the option to define both piecewise and polynomial costs within a single function call, further enhancing the versatility of the implementation.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Piecewise-Linear-Cost","page":"Power System Model","title":"Piecewise Linear Cost","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can also create a piecewise linear cost function, for example, let us create the reactive power cost function for the same generator using the following code:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", reactive = 1, piecewise = [0.11 12.3; 0.15 16.8])\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The first column denotes the generator's output reactive powers in per-units, while the second column specifies the corresponding costs for the specified reactive power in currency/hr. Thus, the data is stored exactly as entered:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.reactive.piecewise[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-4","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Changing input units from per-units (pu) can be particularly useful since cost functions are usually related to SI units. Let us set active powers in megawatts (MW) and reactive powers in megavolt-amperes reactive (MVAr):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@power(MW, MVAr, pu)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now, we can add the quadratic polynomial function using megawatts:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", active = 2, polynomial = [0.11; 5.0; 150.0])","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After inspecting the resulting cost data, we can see that it is the same as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.active.polynomial[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, we can define the linear piecewise cost using megavolt-amperes reactive:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", reactive = 1, piecewise = [11.0 12.3; 15.0 16.8])\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Upon inspection, we can see that the stored data is the same as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.reactive.piecewise[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nThe cost! function not only adds costs but also allows users to update previously defined cost functions. This functionality is particularly valuable in optimal power flow analyses, as it allows users to modify generator power costs without the need to recreate models from scratch.","category":"page"},{"location":"background/installation/#InstallationGuide","page":"Installation Guide","title":"Installation Guide","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"JuliaGrid is compatible with Julia version 1.9 and later. To get started with JuliaGrid, users should first install Julia and consider using a code editor for a smoother coding experience.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-Julia","page":"Installation Guide","title":"Install Julia","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"Begin by downloading and installing Julia. We can choose either the Current Stable Release or the Long-term Support Release.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"The Current Stable Release is the most recent version of Julia, providing access to the latest features and typically offering better performance. For most users, we recommend installing the Current Stable Release. The Long-term Support Release is an older version of Julia that has continued to receive bug and security fixes. However, it may not have the latest features or performance improvements.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-Code-Editor","page":"Installation Guide","title":"Install Code Editor","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"For a smoother development experience, we recommend using a code editor. While you can write Julia code in any text editor, using an integrated development environment (IDE) makes coding easier and more efficient. We suggest installing Visual Studio Code, which provides excellent support for Julia through its dedicated Julia extension. Visual Studio Code offers features like syntax highlighting, debugging, and autocompletion, making it an ideal choice for both beginners and experienced users.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"The Julia extension for Visual Studio Code includes built-in dynamic autocompletion, inline results, plot pane, integrated REPL, variable view, code navigation, and many other advanced language features. For a step-by-step guide on how to use Julia in Visual Studio Code, you can follow the tutorial available here.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-JuliaGrid","page":"Installation Guide","title":"Install JuliaGrid","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"To get the JuliaGrid package installed, execute the following Julia command:","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"import Pkg\nPkg.add(\"JuliaGrid\")","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"When a new version of JuliaGrid is released, you can update it with the following command:","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"import Pkg\nPkg.update(\"JuliaGrid\")","category":"page"},{"location":"tutorials/perunit/#PerUnitSystem","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"In power system modeling and analysis, variables and parameters are often normalized using the per-unit system. The per-unit system is particularly advantageous for analyzing networks with multiple voltage levels connected by transformers with different turns ratios.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"In static scenarios, there are four key quantities of interest: voltage, current, power, and impedance or admittance. Defining a per-unit system requires selecting base values for each of these quantities. However, since these quantities are interconnected by various laws, the choice of base values cannot be arbitrary. Typically, the base quantities are chosen as voltage and power, with the base current and impedance (or admittance) then calculated accordingly. Usually, base quantities are selected as follows:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"three-phase apparent power S_3phi(textb),\nline-to-line voltage V_LL(textb).","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"While the value of three-phase apparent power is unique across the entire system, multiple line-to-line base voltages are used to account for the different voltage zones created by transformers.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nSince balanced three-phase power systems are treated as a single line with a neutral return, confusion may arise regarding the relationship between the per-unit values of line voltages and phase voltages, as well as between the per-unit values of single-phase and three-phase powers [7]. To clarify these relationships, we will systematically explore the conversions between the per-unit and SI systems below.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Powers","page":"Per-Unit System","title":"Powers","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Let us consider the three-phase apparent power expressed in SI units, denoted as S_3phi(textsi). To convert this into the per-unit system, we divide it by the base power:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"S_3phi(textpu) = cfracS_3phi(textsi)S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Now, let us examine the power of a single phase and convert it to the per-unit system:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"S_1phi(textpu) = cfracS_1phi(textsi)S_1phi(textb) = cfracS_3phi(textsi)3 cfrac3S_3phi(textb) = cfracS_3phi(textsi)S_3phi(textb) = S_3phi(textpu)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"This indicates that in the per-unit system, there is no distinction between three-phase and single-phase powers. The type of power only becomes relevant when converting back from per-unit to SI units, and vice versa.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nAs is standard practice, even if all simulations utilize a single-phase equivalent, input powers provided in SI units are assumed to represent three-phase powers. Similarly, if simulation results are displayed in SI units, they are considered to be three-phase powers, as we have selected three-phase power as the base value.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Voltages","page":"Per-Unit System","title":"Voltages","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Format for input data that JuliaGrid uses required value for base voltage per each bus, and those values represent the line-to-line voltages. On the other hand, in all analyses we are working with line-to-neutral voltages. To convert a line-to-neutral voltage given in SI units V_LN(textsi) to per-unit form V_LN(textpu), or vice versa, we use the formula:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"V_LN(textpu) = cfracsqrt3V_LN(textsi)V_LL(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nSimilarly to power, JuliaGrid simulations use a single-phase equivalent. Voltage values specified in volts correspond to line-to-neutral values, while base voltages are expected to be provided as line-to-line values.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Impedances","page":"Per-Unit System","title":"Impedances","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Let us first consider the line itself, excluding transformers. The base impedance of the line is given by:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_L(textb) = cfracV_LL(textb)^2S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"If the impedance is provided in ohms, its value in the per-unit system is:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_L(textpu) = cfracZ_L(textsi)Z_L(textb) = cfracZ_L(textsi) S_3phi(textb)V_LL(textb)^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"A common question that arises is which base voltage should be used for the line, considering the two ends of the line (from-bus and to-bus). The key assumption here is that the base voltages correspond to the nominal voltages of the transformers. Therefore, when the user defines base voltages, JuliaGrid assumes these voltages represent the nominal voltages of the transformers, implying that the base voltages on both the from-bus and to-bus ends of the line will be the same.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Now, let us consider the transformer. The base voltages at the from-bus end (primary side) V_LLF(textb), and the to-bus end (secondary side) V_LLT(textb), will generally be different. This requires us to define a conversion method for impedance. Typically, when impedance is given in ohms, it refers to the primary side of the transformer, denoted as Z_F(textsi), while the impedance in our unified branch model refers to the secondary side, denoted as Z_T(textsi). To convert the impedance from the from-bus end to the to-bus end, we use:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textsi) = cfracZ_F(textsi)m^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"where m is the effective turns ratio, calculated as:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"m = tau cfracV_LLF(textb)V_LLT(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"with tau is off-nominal turns ratio. This equation provides the impedance on the to-bus end of the branch or the secondary side of the transformer in ohms.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"To convert this impedance to the per-unit system, we use the base impedance for the secondary side:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textpu) = cfracZ_T(textsi)Z_T(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"where:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textb) = cfracV_LLT(textb)^2S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Substituting the previous expressions, we obtain the following formula for the impedance on the secondary side in per-unit system:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textpu) = cfracZ_F(textsi) S_3phi(textb)tau^2 V_LLF(textb)^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"This formula applies to both lines and transformers. For a line, where tau = 1, the formula simplifies and becomes the same as the impedance equation for a line.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nIn the case of a transformer, if impedances or admittances are provided in SI units, they must be specified for the primary side (from-bus end).","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Currents","page":"Per-Unit System","title":"Currents","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Once the base power and base voltage values are set, we can calculate the base current flowing through a line or branch as follows:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"I_L(textb) = cfracS_3phi(textb)sqrt3V_LL(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"When we transform currents that are given in SI unit to per-unit, or vice versa, we use the following formula:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"I_L(textpu) = cfracI_L(textsi)I_L(textb) = cfracsqrt3I_L(textsi)V_LL(textb)S_3phi(textb)","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUStateEstimationTutorials","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the AC model:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of PMUs mathcalM equiv barmathcalP into the graph mathcalG, that capture both bus voltage and branch current phasors. To construct the linear PMU state estimation model, we represent the vector of state variables, as well as phasor measurements, in the rectangular coordinate system. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEModelTutorials","page":"PMU State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Initially, PMUs output phasor measurements in polar coordinates. However, these measurements can be interpreted in rectangular coordinates, where the real and imaginary parts of bus voltages and branch current phasors serve as measurements. Additionally, to obtain the linear system of equations, we observe a vector of state variables in rectangular coordinates mathbf x equivmathbfV_textremathbfV_textim:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"mathbfV_mathrmre =bigRe(barV_1)dotsRe(barV_n)big^T, representing the real parts of complex bus voltages,\nmathbfV_mathrmim =bigIm(barV_1)dotsIm(barV_n)big^T, representing the imaginary parts of complex bus voltages.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, the total number of state variables is 2n. It is worth noting that in this approach to state estimation, we do not require the slack bus.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The primary drawback of this method stems from measurement errors, which are associated with polar coordinates. Consequently, the covariance matrix must be transformed from polar to rectangular coordinates. As a result, errors from a single PMU are correlated, leading to a non-diagonal covariance matrix. Despite this, the covariance matrix is commonly treated as diagonal, impacting the state estimation accuracy in such scenarios.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, the model includes real and imaginary parts of bus voltage and current phasor measurements from the set mathcalM, contributing to the formulation of a linear system of equations:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbfh(mathbf x)= h_1(mathbf x), dots, h_k(mathbf x)^T represents the vector of linear measurement functions, where k = 2barmathcalP is the number of measurement functions, mathbfz = z_1dotsz_k^T denotes the vector of measurement values, and mathbfu = u_1dotsu_k^T represents the vector of measurement errors.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"These errors are assumed to follow a Gaussian distribution with a zero mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In summary, upon defining the PMU, each i-th PMU is associated with two measurement functions h_2i-1(mathbf x), h_2i(mathbf x), along with their respective measurement values z_2i-1, z_2i, as well as their variances v_2i-1, v_2i, and possibly covariances w_2i-1, w_2i.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Bus-Voltage-Phasor-Measurements","page":"PMU State Estimation","title":"Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"When a PMU (V_i theta_i) in barmathcalP is introduced at bus i in mathcalN in this type of state estimation, users specify the measurement values, variances, and measurement functions of vectors as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barV_i) z_Im(barV_i) mathbfv = v_Re(barV_i) v_Im(barV_i) mathbfh(mathbf x) = h_Re(barV_i)(mathbf x) h_Im(barV_i)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"V₂, θ₂\", bus = 2, magnitude = 0.9, angle = -0.1,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barV_i) = z_V_i cos z_theta_i\n z_Im(barV_i) = z_V_i sin z_theta_i\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)right^2 =\n v_V_i (cos z_theta_i)^2 + v_theta_i (z_V_i sin z_theta_i)^2\n v_Im(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)right^2 =\n v_V_i (sin z_theta_i)^2 + v_theta_i (z_V_i cos z_theta_i)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Lastly, the functions defining the bus voltage phasor measurement are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barV_i)(mathbf x) = Re(barV_i)\n h_Im(barV_i)(mathbf x) = Im(barV_i)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" cfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial Re(barV_i)=1 \n cfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial Im(barV_i)=1","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the previous example, the user neglected the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barV_i) w_Im(barV_i)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"V₃, θ₃\", bus = 3, magnitude = 0.9, angle = -0.2,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) =\n v_V_i cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) +\n v_theta_i cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"which results in the solution:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) = cos z_theta_i sin z_theta_i(v_V_i - v_theta_i z_V_i^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#From-Bus-End-Current-Phasor-Measurements","page":"PMU State Estimation","title":"From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the user chooses to include phasor measurement (I_ij psi_ij) in barmathcalP in the state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barI_ij) z_Im(barI_ij) mathbfv = v_Re(barI_ij) v_Im(barI_ij) mathbfh(mathbf x) = h_Re(barI_ij)(mathbf x) h_Im(barI_ij)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₂₃, ψ₂₃\", from = 3, magnitude = 0.3, angle = 0.4,\nvarianceMagnitude = 1e-3, varianceAngle = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barI_ij) = z_I_ij cos z_psi_ij\n z_Im(barI_ij) = z_I_ij sin z_psi_ij\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barI_ij) = v_I_ij (cos z_psi_ij)^2 + v_psi_ij (z_I_ij sin z_psi_ij)^2 \n v_Im(barI_ij) = v_I_ij (sin z_psi_ij)^2 + v_psi_ij (z_I_ij cos z_psi_ij)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The functions defining the current phasor measurement at the from-bus end are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barI_ij)(mathbf x) = A Re(barV_i) - B Im(barV_i) - left(C cosphi_ij - D sin phi_ijright) Re(barV_j) + left(Csin phi_ij + Dcos phi_ij right) Im(barV_j) \n h_Im(barI_ij)(mathbf x) = B Re(barV_i) + A Im(barV_i) - left(C sin phi_ij + D cosphi_ijright) Re(barV_j) - left(Ccos phi_ij - Dsin phi_ij right)Im(barV_j)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n A = cfracg_ij + g_textsijtau_ij^2\n B = cfracb_ij+b_textsij tau_ij^2\n C = cfracg_ijtau_ij\n D = cfracb_ijtau_ij\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Re(barV_i) =\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial Im(barV_i) = A \n cfracmathrm partialh_Re(barI_ij)(mathbf x) mathrm partial Re(barV_j) =\n cfracmathrm partialh_Im(barI_ij)(mathbf x) mathrm partial Im(barV_j) =\n - left(C cosphi_ij - D sin phi_ijright)\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Im(barV_i) =-\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial Re(barV_i) =\n -B \n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Im(barV_j) = -\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partialRe(barV_j) =\n left(Csin phi_ij + D cos phi_ij right)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barI_ij) w_Im(barI_ij)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₁₃, ψ₁₃\", from = 2, magnitude = 0.3, angle = -0.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barI_ij) = w_Im(barI_ij) = sin z_psi_ij cos z_psi_ij(v_I_ij - v_psi_ij z_I_ij^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#To-Bus-End-Current-Phasor-Measurements","page":"PMU State Estimation","title":"To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the user chooses to include phasor measurement (I_ji psi_ji) in barmathcalP in the state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barI_ji) z_Im(barI_ji) mathbfv = v_Re(barI_ji) v_Im(barI_ji) mathbfh(mathbf x) = h_Re(barI_ji)(mathbf x) h_Im(barI_ji)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₃₂, ψ₃₂\", to = 3, magnitude = 0.3, angle = -2.9,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barI_ji) = z_I_ji cos z_psi_ji\n z_Im(barI_ji) = z_I_ji sin z_psi_ji\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barI_ji) = v_I_ji (cos z_psi_ji)^2 + v_psi_ji (z_I_ji sin z_psi_ji)^2 \n v_Im(barI_ji) = v_I_ji (sin z_psi_ji)^2 + v_psi_ji (z_I_ji cos z_psi_ji)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The functions defining the current phasor measurement at the to-bus end are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barI_ji)(mathbf x) = tau_ij^2 A Re(barV_j) - tau_ij^2 B Im(barV_j) - left(C cosphi_ij + D sin phi_ijright) Re(barV_i) - left( Csin phi_ij - Dcos phi_ij right) Im(barV_i)\n h_Im(barI_ji)(mathbf x) = tau_ij^2 B Re(barV_j) + tau_ij^2 A Im(barV_j) + left(C sin phi_ij - D cosphi_ij right) Re(barV_i) - left(Ccos phi_ij + Dsin phi_ijright) Im(barV_i)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Re(barV_i) =\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Im(barV_i) =\n - left(C cosphi_ij + D sin phi_ijright)\n cfracmathrm partialh_Re(barI_ji)(mathbf x) mathrm partial Re(barV_j) =\n cfracmathrm partialh_Im(barI_ji)(mathbf x) mathrm partial Im(barV_j) = tau_ij^2A\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Im(barV_i) = -\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Re(barV_i) =\n -left(Csin phi_ij - Dcos phi_ij right) \n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Im(barV_j) = -\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Re(barV_j) =\n -tau_ij^2B\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As before, we are neglecting the covariances between the real and imaginary parts of the measurement. If desired, we can include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barI_ji) w_Im(barI_ji)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₃₁, ψ₃₁\", to = 2, magnitude = 0.3, angle = 2.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barI_ji) = w_Im(barI_ji) = sin z_psi_ji cos z_psi_ji(v_I_ji - v_psi_ji z_I_ji^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEWLSStateEstimationTutorials","page":"PMU State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The solution to the PMU state estimation problem is determined by solving the linear weighted least-squares (WLS) problem, represented by the following formula:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf H^T bm Sigma^-1 mathbf H mathbf x = mathbf H^T bm Sigma^-1 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbf z in mathbb R^k denotes the vector of measurement values, mathbf H in mathbb R^k times 2n represents the coefficient matrix, and bm Sigma in mathbb R^k times k is the measurement error covariance matrix.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Implementation","page":"PMU State Estimation","title":"Implementation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid initiates the PMU state estimation framework by setting up the WLS model, as illustrated in the following:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Coefficient-Matrix","page":"PMU State Estimation","title":"Coefficient Matrix","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Using the above-described equations, JuliaGrid forms the coefficient matrix mathbfH in mathbbR^k times 2n:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐇 = analysis.method.coefficient","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this matrix, each row corresponds to a specific measurement in the rectangular coordinate system. Therefore, the i-th PMU is associated with the 2i - 1 index of the row, representing the real part of the phasor measurement, while the 2i row corresponds to the imaginary part of the phasor measurement. Columns are ordered based on how the state variables are defined mathbf x equivmathbfV_textremathbfV_textim.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Precision-Matrix","page":"PMU State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid opts not to retain the covariance matrix bm Sigma but rather stores its inverse, the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. The order of these values corresponds to the description provided for the coefficient matrix. Users can access these values using the following command:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The precision matrix does not maintain a diagonal form, indicating that correlations between the real and imaginary parts of the phasor measurements are included in the model. To ignore these correlations, simply omit the correlated keyword within the function that adds a PMU. For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\n\n@pmu(label = \"PMU ?\", noise = false)\naddPmu!(system, device; bus = 1, magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = 2, magnitude = 0.87, angle = -0.15)\naddPmu!(system, device; from = 1, magnitude = 0.30, angle = -0.71)\naddPmu!(system, device; from = 2, magnitude = 0.31, angle = -0.49)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following this, we recreate the WLS state estimation model:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon inspection, it becomes evident that the precision matrix maintains a diagonal structure:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Mean-Vector","page":"PMU State Estimation","title":"Mean Vector","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To retrieve the vector mathbf z, containing the means of Gaussian distributions for each measurement, users can utilize:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"These values represent measurement values in the rectangular coordinate system as described earlier.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Estimate-of-State-Variables","page":"PMU State Estimation","title":"Estimate of State Variables","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Next, the WLS equation is solved to obtain the estimate of state variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\thatmathbf x = mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T bm Sigma^-1 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This process is executed using the solve! function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The initial step involves the LU factorization of the gain matrix:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf G = mathbf H^T bm Sigma^-1 mathbf H = mathbf L mathbf U","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the gain matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Access to the factorized gain matrix is available through:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Finally, JuliaGrid obtains the solution in the rectangular coordinate system and then transforms these solutions into the standard form given in the polar coordinate system.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, can be retrieved using the variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nIt is essential to note that the slack bus does not exist in the case of the PMU state estimation model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEOrthogonalWLSStateEstimationTutorials","page":"PMU State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2]. This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can employ an alternative approach:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device, Orthogonal)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf H^T mathbf W mathbf H hatmathbf x = mathbf H^T mathbf W mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf H hatmathbf x = left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH^T barmathbfH hatmathbf x = barmathbfH^T barmathbfz","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH = mathbf W^12 mathbf H barmathbfz = mathbf W^12 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"At this point, QR factorization is performed on the rectangular matrix:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH = mathbf W^12 mathbf H = mathbfQmathbfR","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Executing this procedure involves the solve! function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the solution, JuliaGrid avoids materializing the orthogonal matrix mathbfQ and proceeds to solve the system, resulting in the estimate of bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, where i in mathcalN:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEBadDataTutorials","page":"PMU State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = 3, magnitude = 2.5, angle = 0.1)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we will construct the WLS state estimation model and solve it:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals in the rectangular coordinate system based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" r_i = z_i - h_i(hat mathbf x) i in mathcalM","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf H mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"is removed from the PMU model and marked as out-of-service. Specifically, either the real or imaginary part of the corresponding measurement is identified as the outlier. Consequently, both parts of the measurement are removed from the PMU state estimation model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we can immediately solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSELAVTutorials","page":"PMU State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"It can be demonstrated that the problem can be expressed as a linear programming problem. This section outlines the method as described in [5, Sec. 6.5]. To revisit, we consider the system of linear equations:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz=mathbfh(mathbf x)+mathbfu+mathbfw","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize mathbf a^T mathbf r\n textsubjectto mathbfz - mathbfH mathbf x =mathbf r\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbf a in mathbb R^k is the vector with all entries equal to one, and mathbf r represents the vector of measurement residuals. Let bm eta be defined in a manner that ensures:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf r preceq bm eta","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"and replace the above inequality with two equalities using the introduction of two non-negative slack variables mathbf q in mathbb R_ge 0^k and mathbf w in mathbb R_ge 0^k:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r - mathbf q = -bm eta \n mathbf r + mathbf w = bm eta\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us now define four additional non-negative variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf x_x in mathbb R_ge 0^n mathbf x_y in mathbb R_ge 0^n \n mathbf r_x in mathbb R_ge 0^k mathbf r_y in mathbb R_ge 0^k","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf x = mathbf x_x - mathbf x_y mathbf r = mathbf r_x - mathbf r_y\n mathbf r_x = cfrac12 mathbf q mathbf r_y = cfrac12 mathbf w","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r - 2mathbf r_x = -2bm eta \n mathbf r + 2 mathbf r_y = 2bm eta\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"that is:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r_x + mathbf r_y = bm eta mathbf r = mathbf r_x - mathbf r_y\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize mathbf a^T (mathbf r_x + mathbf r_y)\n textsubjectto mathbfH(mathbf x_x - mathbf x_y) + mathbf r_x - mathbf r_y = mathbfz \n mathbf x_x succeq mathbf 0 mathbf x_y succeq mathbf 0 \n mathbf r_x succeq mathbf 0 mathbf r_y succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As a result, we obtain optimal values for the four additional non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" hatmathbf x = mathbf x_x - mathbf x_y","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can retrieve the estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, using:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#optimalpmu","page":"PMU State Estimation","title":"Optimal PMU Placement","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid utilizes the optimal PMU placement algorithm proposed in [23]. The optimal positioning of PMUs is framed as an integer linear programming problem, expressed as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize sum_i=1^n d_i\n textsubjectto mathbf A mathbf d ge mathbf a\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, the vector mathbf d = d_1dotsd_n^T serves as the optimization variable, where d_i in mathbbF = 01 is the PMU placement or a binary decision variable associated with the bus i in mathcalN. The all-one vector mathbf a is of dimension n. The binary connectivity matrix mathbf A in mathbbF^n times n can be directly derived from the bus nodal matrix mathbf Y by converting its entries into binary form [24].","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, we obtain the binary vector mathbf d = d_1dotsd_n^T, where d_i = 1, i in mathcalN, suggests that a PMU should be placed at bus i. The primary aim of PMU placement in the power system is to determine a minimal set of PMUs such that the entire system is observable without relying on traditional measurements [23]. Specifically, when we observe d_i = 1, it indicates that the PMU is installed at bus i in mathcalN to measure bus voltage phasor as well as all current phasors across branches incident to bus i.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Determining the optimal PMU placement involves analyzing the created power system. For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using GLPK\nusing JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 2, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nplacement = pmuPlacement(system, GLPK.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The placement variable contains data regarding the optimal placement of measurements. It lists all buses i in mathcalN that satisfy d_i = 1:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.bus","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This PMU installed at bus 2 will measure the bus voltage phasor at the corresponding bus and all current phasors at the branches incident to bus 2 located at the from-bus or to-bus ends. These data are stored in the variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.from\nplacement.to","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUPowerAnalysisTutorials","page":"PMU State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-Injections","page":"PMU State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUGeneratorPowerInjectionsManual","page":"PMU State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can calculate the active and reactive power injections supplied by generators at each bus i in mathcalN by summing the active and reactive power injections and the active and reactive power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n P_textpi = P_i + P_textdi\n Q_textpi = Q_i + Q_textdi\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The active and reactive power injections from the generators at each bus are stored as vectors, denoted by mathbfP_textp = P_textpi and mathbfQ_textp = Q_textpi, which can be obtained using:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₚ = analysis.power.supply.active\n𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Bus-Shunt-Elements","page":"PMU State Estimation","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-Flows","page":"PMU State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Branch-Shunt-Elements","page":"PMU State Estimation","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Branch-Series-Elements","page":"PMU State Estimation","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUCurrentAnalysisTutorials","page":"PMU State Estimation","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-Injections","page":"PMU State Estimation","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-Flows","page":"PMU State Estimation","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-at-Branch-Series-Elements","page":"PMU State Estimation","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/powerFlow/#PowerFlowAPI","page":"Power Flow","title":"Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"For further information on this topic, please see the AC Power Flow or DC Power Flow sections of the Manual. Below, we have provided a list of functions that can be utilized for power flow analysis.","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"To load power flow API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"using JuliaGrid","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#AC-Power-Flow","page":"Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"newtonRaphson\nfastNewtonRaphsonBX\nfastNewtonRaphsonXB\ngaussSeidel\nmismatch!\nsolve!\nstartingVoltage!\nreactiveLimit!\nadjustAngle!","category":"page"},{"location":"api/powerFlow/#DC-Power-Flow","page":"Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"dcPowerFlow\nsolve!","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#AC-Power-Flow-2","page":"Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"newtonRaphson\nfastNewtonRaphsonBX\nfastNewtonRaphsonXB\ngaussSeidel\nmismatch!(::PowerSystem, ::ACPowerFlow{NewtonRaphson})\nsolve!(::PowerSystem, ::ACPowerFlow{NewtonRaphson})\nstartingVoltage!\nreactiveLimit!\nadjustAngle!","category":"page"},{"location":"api/powerFlow/#JuliaGrid.newtonRaphson","page":"Power Flow","title":"JuliaGrid.newtonRaphson","text":"newtonRaphson(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the Newton-Raphson method to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrix, its factorization, mismatches, increments, and indices.\n\nExamples\n\nSet up the Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\n\nSet up the Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.fastNewtonRaphsonBX","page":"Power Flow","title":"JuliaGrid.fastNewtonRaphsonBX","text":"fastNewtonRaphsonBX(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the fast Newton-Raphson method of version BX to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrices, their factorizations, mismatches, increments, and indices.\n\nExamples\n\nSet up the fast Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonBX(system)\n\nSet up the fast Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonBX(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.fastNewtonRaphsonXB","page":"Power Flow","title":"JuliaGrid.fastNewtonRaphsonXB","text":"fastNewtonRaphsonXB(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the fast Newton-Raphson method of version XB to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrices, their factorizations, mismatches, increments, and indices.\n\nExamples\n\nSet up the fast Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonXB(system)\n\nSet up the fast Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonXB(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.gaussSeidel","page":"Power Flow","title":"JuliaGrid.gaussSeidel","text":"gaussSeidel(system::PowerSystem)\n\nThe function sets up the Gauss-Seidel method to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The bus complex voltages and indices.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = gaussSeidel(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.mismatch!-Tuple{PowerSystem, ACPowerFlow{NewtonRaphson}}","page":"Power Flow","title":"JuliaGrid.mismatch!","text":"mismatch!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function calculates both active and reactive power injection mismatches.\n\nUpdates\n\nThis function updates the mismatch variables in the Newton-Raphson and fast Newton-Raphson methods. It should be employed during the iteration loop before invoking the solve! function.\n\nReturns\n\nThe function returns maximum absolute values of the active and reactive power injection mismatches, which can be utilized to terminate the iteration loop of the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel methods employed to solve the AC power flow problem.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nmismatch!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/powerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, ACPowerFlow{NewtonRaphson}}","page":"Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function employs the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel method to solve the AC power flow model and calculate bus voltage magnitudes and angles.\n\nAfter the mismatch! function is called, this function should be executed to perform a single iteration of the method.\n\nUpdates\n\nThe calculated voltages are stored in the voltage field of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"method"},{"location":"api/powerFlow/#JuliaGrid.startingVoltage!","page":"Power Flow","title":"JuliaGrid.startingVoltage!","text":"startingVoltage!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function extracts bus voltage magnitudes and angles from the PowerSystem composite type and assigns them to the ACPowerFlow type, enabling users to initialize voltage values as required.\n\nUpdates\n\nThis function only updates the voltage field of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingVoltage!(system, analysis)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.reactiveLimit!","page":"Power Flow","title":"JuliaGrid.reactiveLimit!","text":"reactiveLimit!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function verifies whether the generators in a power system exceed their reactive power limits. This is done by setting the reactive power of the generators to within the limits if they are violated after determining the bus voltage magnitudes and angles. If the limits are violated, the corresponding generator buses or the slack bus are converted to demand buses.\n\nUpdates\n\nThe function assigns values to the generator.output.active and bus.supply.active variables of the PowerSystem type.\n\nAdditionally, it examines the reactive powers of the generators and adjusts them to their maximum or minimum values if they exceed the specified threshold. This results in the modification of the variable generator.output.reactive of the PowerSystem type accordingly.\n\nAs a result of this adjustment, the bus.supply.reactive variable is also updated, and the bus types specified in bus.layout.type are modified. If the slack bus is converted, the bus.layout.slack field is correspondingly adjusted.\n\nReturns\n\nThe function returns the variable to indicate which buses violate the limits, with -1 indicating a violation of the minimum limits and 1 indicating a violation of the maximum limits.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nviolate = reactiveLimit!(system, analysis)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.adjustAngle!","page":"Power Flow","title":"JuliaGrid.adjustAngle!","text":"adjustAngle!(system::PowerSystem, analysis::ACPowerFlow; slack)\n\nThe function modifies the bus voltage angles based on a different slack bus than the one identified by the bus.layout.slack field.\n\nFor instance, if the reactive power of the generator exceeds the limit on the slack bus, the reactiveLimit! function will change that bus to the demand bus and designate the first generator bus in the sequence as the new slack bus. After obtaining the updated AC power flow solution based on the new slack bus, it is possible to adjust the voltage angles to align with the angle of the original slack bus.\n\nKeyword\n\nThe slack keyword specifies the bus label for which we want to adjust voltage angles.\n\nUpdates\n\nThis function only updates the voltage.angle variable of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nreactiveLimit!(system, analysis)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nadjustAngle!(system, analysis; slack = 1)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#DC-Power-Flow-2","page":"Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"dcPowerFlow\nsolve!(::PowerSystem, ::DCPowerFlow)","category":"page"},{"location":"api/powerFlow/#JuliaGrid.dcPowerFlow","page":"Power Flow","title":"JuliaGrid.dcPowerFlow","text":"dcPowerFlow(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the framework to solve the DC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nLDLt: utilizes LDLt factorization,\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCPowerFlow type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The factorized nodal matrix.\n\nExamples\n\nSet up the DC power flow utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\n\nSet up the DC power flow utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, DCPowerFlow}","page":"Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCPowerFlow)\n\nThe function solves the DC power flow model and calculates bus voltage angles.\n\nUpdates\n\nThe calculated voltage angles are stored in the voltage field of the DCPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"tutorials/acStateEstimation/#ACStateEstimationTutorials","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the AC model:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of measurement devices mathcalM into the graph mathcalG. The AC state estimation includes a set of voltmeters mathcalV, ammeters mathcalI, wattmeters mathcalP, varmeters mathcalQ, and PMUs barmathcalP, with PMUs being able to integrate into AC state estimation in either rectangular coordinates or polar coordinates. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type at this stage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACSEModelTutorials","page":"AC State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In accordance with the AC Model, the AC state estimation treats bus voltages as state variables, which we denoted by mathbf x equiv bm Theta mathbfV^T. The state vector encompasses two components:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"bm Theta in mathbbR^n-1, representing bus voltage angles,\nmathbf V in mathbbR^n, representing bus voltage magnitudes.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, the total number of state variables is n_textu = 2n-1, accounting for the fact that the voltage angle for the slack bus is known.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Within the JuliaGrid framework for AC state estimation, the methodology encompasses bus voltage magnitudes, branch current magnitudes, active powers, reactive powers, and phasor measurements. These measurements contribute to the construction of a nonlinear system of equations:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, mathbfh(mathbf x)= h_1(mathbf x), dots, h_k(mathbf x)^T represents the vector of nonlinear measurement functions, where k is the number of measurements, mathbfz = z_1dotsz_k^T denotes the vector of measurement values, and mathbfu = u_1dotsu_k^T represents the vector of measurement errors. It is worth noting that the number of equations in the system is equal to k = mathcalV cup mathcalI cup mathcalP cup mathcalQ + 2barmathcalP.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These errors are assumed to follow a Gaussian distribution with a zero mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T. These covariances exist only if PMUs are observed in rectangular coordinates and correlation is required.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, the nonlinear system of equations is structured according to the specific devices:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginbmatrix\n mathbfz_mathcalV3pt\n mathbfz_mathcalI3pt\n mathbfz_mathcalP3pt\n mathbfz_mathcalQ3pt\n mathbfz_barmathcalP\n endbmatrix =\n beginbmatrix\n mathbfh_mathcalV(mathbf x)3pt\n mathbfh_mathcalI(mathbf x)3pt\n mathbfh_mathcalP(mathbf x)3pt\n mathbfh_mathcalQ(mathbf x)3pt\n mathbfh_barmathcalP(mathbf x)\n endbmatrix +\n beginbmatrix\n mathbfu_mathcalV3pt\n mathbfu_mathcalI3pt\n mathbfu_mathcalP3pt\n mathbfu_mathcalQ3pt\n mathbfu_barmathcalP\n endbmatrix","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Please note that each error vector, denoted as mathbfu_i, where i in mathcalV mathcalI mathcalP mathcalQ, is associated with the variance vector mathbfv_i. However, for PMUs, the error vector mathbfu_barmathcalP, along with its variance vector mathbfv_barmathcalP, can also be associated with the covariance vector mathbfw_barmathcalP.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In summary, upon user definition of the measurement devices, each i-th legacy measurement device is linked to the measurement function h_i(mathbf x), the corresponding measurement value z_i, and the measurement variance v_i. Meanwhile, each i-th PMU is associated with two measurement functions h_2i-1(mathbf x), h_2i(mathbf x), along with their respective measurement values z_2i-1, z_2i, as well as their variances v_2i-1, v_2i, and possibly covariances w_2i-1, w_2i.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Typically, the AC state estimator is obtained using the Gauss-Newton method or its variation, which involves constructing the Jacobian matrix. Therefore, in addition to the aforementioned elements, we also need Jacobian expressions corresponding to the measurement functions, which are also provided below.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Bus-Voltage-Magnitude-Measurements","page":"AC State Estimation","title":"Bus Voltage Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a voltmeter V_i in mathcalV at bus i in mathcalN, users specify the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalV = z_V_i mathbfv_mathcalV = v_V_i mathbfh_mathcalV(mathbf x) = h_V_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; label = \"V₁\", bus = 1, magnitude = 1.0, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the bus voltage magnitude measurement function is simply defined as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_V_i(mathbf x) = V_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expression:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" \tcfracmathrm partialh_V_i(mathbf x) mathrm partial V_i=1","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#FromCurrentMagnitudeMeasurements","page":"AC State Estimation","title":"From-Bus End Current Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing an ammeter at branch (ij) in mathcalE, it can be placed at the from-bus end, denoted as I_ij in mathcalI, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalI = z_I_ij mathbfv_mathcalI = v_I_ij mathbfh_mathcalI(mathbf x) = h_I_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addAmmeter!(system, device; label = \"I₁₂\", from = 1, magnitude = 0.3, variance = 1e-2)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, following the guidelines outlined in the AC Model, the function defining the current magnitude at the from-bus end is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_I_ij(mathbf x) = sqrtA_I_ijV_i^2 + B_I_ijV_j^2 - 2C_I_ij cos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" begingathered\n A_I_ij = cfrac(g_ij + g_textsi)^2+(b_ij+b_textsi)^2tau_ij^4 B_I_ij = cfracg_ij^2+b_ij^2tau_ij^2 \n C_I_ij = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij^3 D_I_ij = cfracg_ijb_textsi - b_ijg_textsitau_ij^3\n endgathered","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_I_ij(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_I_ij(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_I_ij(mathbf x)mathrm partial theta_j =\n cfrac C_I_ijsin(theta_ij - phi_ij) + D_I_ijcos(theta_ij - phi_ij)V_i V_jh_I_ij(mathbf x) \n cfracmathrm partialh_I_ij(mathbf x)mathrm partial V_i =\n cfracA_I_ijV_i - C_I_ijcos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_jh_I_ij(mathbf x) \n cfracmathrm partialh_I_ij(mathbf x)mathrm partial V_j =\n cfracB_I_ijV_j - C_I_ijcos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_ih_I_ij(mathbf x) \n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ToCurrentMagnitudeMeasurements","page":"AC State Estimation","title":"To-Bus End Current Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In addition to the scenario where we add ammeters at the from-bus end, an ammeter can also be positioned at the to-bus end, denoted as I_ji in mathcalI, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalI = z_I_ji mathbfv_mathcalI = v_I_ji mathbfh_mathcalI(mathbf x) = h_I_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addAmmeter!(system, device; label = \"I₂₁\", to = 1, magnitude = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, the measurement function is as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_I_ji(mathbf x) = sqrtA_I_jiV_i^2 + B_I_jiV_j^2 - 2C_I_ji cos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" begingathered\n A_I_ji = cfracg_ij^2+b_ij^2tau_ij^2 B_I_ji = (g_ij + g_textsi)^2+(b_ij+b_textsi)^2 \n C_I_ji = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij D_I_ji = cfracg_ijb_textsi - b_ijg_textsitau_ij\n endgathered","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_I_ji(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_I_ji(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_I_ji(mathbf x)mathrm partial theta_j =\n cfracC_I_jisin(theta_ij - phi_ij) - D_I_jicos(theta_ij- phi_ij)V_i V_jh_I_ji(mathbf x) \n cfracmathrm partialh_I_ji(mathbf x)mathrm partial V_i =\n cfracA_I_jiV_i - C_I_jicos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_jh_I_ji(mathbf x) \n cfracmathrm partialh_I_ji(mathbf x)mathrm partial V_j =\n cfracB_I_jiV_j - C_I_jicos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_ih_I_ji(mathbf x) \n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Active-Power-Injection-Measurements","page":"AC State Estimation","title":"Active Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When adding a wattmeter P_i in mathcalP at bus i in mathcalN, users specify that the wattmeter measures active power injection and define measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_i mathbfv_mathcalP = v_P_i mathbfh_mathcalP(mathbf x) = h_P_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₃\", bus = 3, active = -0.5, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, utilizing the AC Model, we derive the function defining the active power injection as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_i(mathbf x) = V_isumlimits_j in mathcalN_i (G_ijcostheta_ij + B_ijsintheta_ij)V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathcalN_i contains buses incident to bus i, including bus i, with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_i(mathbf x)mathrm partial theta_i =\n V_isum_j in mathcalN_i (-G_ijsintheta_ij+B_ijcostheta_ij)V_j - B_iiV_i^2\n cfracmathrm partialh_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_iV_j \n cfracmathrm partialh_P_i(mathbf x)mathrm partial V_i =\n sum_j in mathcalN_i (G_ijcostheta_ij+B_ij sintheta_ij)V_j + G_ii V_i\n cfracmathrm partialh_P_i(mathbf x)mathrm partial V_j =\n (G_ijcostheta_ij+B_ijsintheta_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#From-Bus-End-Active-Power-Flow-Measurements","page":"AC State Estimation","title":"From-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, when introducing a wattmeter at branch (ij) in mathcalE, users specify that the wattmeter measures active power flow. It can be positioned at the from-bus end, denoted as P_ij in mathcalP, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_ij mathbfv_mathcalP = v_P_ij mathbfh_mathcalP(mathbf x) = h_P_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₁₂\", from = 1, active = 0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function describing active power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_ij(mathbf x) = cfracg_ij + g_textsitau_ij^2 V_i^2 - cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)rightV_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ij(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_P_ij(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_P_ij(mathbf x)mathrm partial V_i =\n 2cfracg_ij + g_textsitau_ij^2 V_i -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)right V_j \n cfracmathrm partialh_P_ij(mathbf x)mathrm partial V_j = -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) + b_ij sin(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#To-Bus-End-Active-Power-Flow-Measurements","page":"AC State Estimation","title":"To-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, a wattmeter can be placed at the to-bus end, denoted as P_ji in mathcalP, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_ji mathbfv_mathcalP = v_P_ji mathbfh_mathcalP(mathbf x) = h_P_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₂₁\", to = 1, active = -0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Thus, the function describing active power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_ji(mathbf x) = (g_ij + g_textsi) V_j^2 - cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij- phi_ij)right V_i V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ji(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_P_ji(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) + b_ijcos(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_P_ji(mathbf x)mathrm partial V_i = -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij - phi_ij)right V_j \n cfracmathrm partialh_P_ji(mathbf x)mathrm partial V_j = 2(g_ij + g_textsi) V_j-\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Reactive-Power-Injection-Measurements","page":"AC State Estimation","title":"Reactive Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When adding a varmeter Q_i in mathcalQ at bus i in mathcalN, users specify that the varmeter measures reactive power injection and define the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_i mathbfv_mathcalQ = v_Q_i mathbfh_mathcalQ(mathbf x) = h_Q_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₃\", bus = 3, reactive = 0, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, utilizing the AC Model, we derive the function defining the reactive power injection as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_i(mathbf x) = V_isumlimits_j in mathcalN_i (G_ijsintheta_ij - B_ijcostheta_ij)V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathcalN_i contains buses incident to bus i, including bus i, with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial theta_i =\n V_isum_j in mathcalN_i (G_ijcostheta_ij+B_ijsintheta_ij)V_j - G_iiV_i^2\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial theta_j =\n -(G_ijcostheta_ij+B_ijsintheta_ij)V_iV_j \n cfracmathrm partialh_Q_i(mathbf x)mathrm partial V_i =\n sum_j in mathcalN_i (G_ijsintheta_ij-B_ijcostheta_ij)V_j - B_iiV_i\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial V_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#From-Bus-End-Reactive-Power-Flow-Measurements","page":"AC State Estimation","title":"From-Bus End Reactive Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, when introducing a varmeter at branch (ij) in mathcalE, users specify that the varmeter measures reactive power flow. It can be positioned at the from-bus end, denoted as Q_ij in mathcalQ, with its measurement value, variance, and measurement function included in vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_ij mathbfv_mathcalQ = v_Q_ij mathbfh_mathcalQ(mathbf x) = h_Q_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₁₂\", from = 1, reactive = 0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function describing reactive power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_ij(mathbf x) = -cfracb_ij + b_textsitau_ij^2 V_i^2 - cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial theta_j = -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial V_i = -\n 2cfracb_ij + b_textsitau_ij^2 V_i -\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_j\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial V_j = -\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#To-Bus-End-Reactive-Power-Flow-Measurements","page":"AC State Estimation","title":"To-Bus End Reactive Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, a varmeter can be placed at the to-bus end, denoted as Q_ji in mathcalQ, with its own measurement value, variance, and measurement function included in vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_ji mathbfv_mathcalQ = v_Q_ji mathbfh_mathcalQ(mathbf x) = h_Q_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₂₁\", to = 1, reactive = -0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Thus, the function describing reactive power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_ji(mathbf x) = -(b_ij + b_textsi) V_j^2 + cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) - b_ijsin(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial V_i =\n cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_j\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial V_j = -\n 2(b_ij + b_textsi) V_j +\n cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-Bus-Voltage-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When a PMU (V_i theta_i) in barmathcalP is introduced at bus i in mathcalN, it will be incorporated into the AC state estimation model using rectangular coordinates by default. It will define the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barV_i) z_Im(barV_i) mathbfv_barmathcalP = v_Re(barV_i) v_Im(barV_i) mathbfh_barmathcalP(mathbf x) = h_Re(barV_i)(mathbf x) h_Im(barV_i)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₂, θ₂\", bus = 2, magnitude = 0.9, angle = -0.1,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barV_i) = z_V_i cos z_theta_i\n z_Im(barV_i) = z_V_i sin z_theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)right^2 =\n v_V_i (cos z_theta_i)^2 + v_theta_i (z_V_i sin z_theta_i)^2\n v_Im(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)right^2 =\n v_V_i (sin z_theta_i)^2 + v_theta_i (z_V_i cos z_theta_i)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Lastly, the functions defining the bus voltage phasor measurement are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barV_i)(mathbf x) = V_icos theta_i\n h_Im(barV_i)(mathbf x) = V_isin theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barV_i)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial theta_i=-V_isin theta_i \n \tcfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial V_i=cos theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barV_i)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial theta_i=V_icos theta_i\n \tcfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial V_i=sin theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barV_i) w_Im(barV_i)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₃, θ₃\", bus = 3, magnitude = 0.9, angle = -0.2,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) =\n v_V_i cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) +\n v_theta_i cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"which results in the solution:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) = cos z_theta_i sin z_theta_i(v_V_i - v_theta_i z_V_i^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-Bus-Voltage-Phasor-Measurements","page":"AC State Estimation","title":"Polar Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (V_i theta_i) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_V_i z_theta_i mathbfv_barmathcalP = v_V_i v_theta_i mathbfh_barmathcalP(mathbf x) = h_V_i(mathbf x) h_theta_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1.0, angle = 0,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-6, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the functions defining the bus voltage phasor measurement are straightforward:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_V_i(mathbf x) = V_i\n h_theta_i(mathbf x) = theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_V_i(mathbf x)mathrm partial V_i=1 \n cfracmathrm partialh_theta_i(mathbf x)mathrm partial theta_i=1\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-From-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a PMU at branch (ij) in mathcalE, it can be placed at the from-bus end, denoted as (I_ij psi_ij) in barmathcalP, and it will be integrated into the AC state estimation model using rectangular coordinates by default. Incorporating current phasor measurements in the polar coordinate system is highly susceptible to ill-conditioned problems, especially when dealing with small values of current magnitudes. This is the reason why we typically include PMUs in the rectangular coordinate system by default.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, here we specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barI_ij) z_Im(barI_ij) mathbfv_barmathcalP = v_Re(barI_ij) v_Im(barI_ij) mathbfh_barmathcalP(mathbf x) = h_Re(barI_ij)(mathbf x) h_Im(barI_ij)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₂₃, ψ₂₃\", from = 3, magnitude = 0.3, angle = 0.4,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barI_ij) = z_I_ij cos z_psi_ij\n z_Im(barI_ij) = z_I_ij sin z_psi_ij\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barI_ij) = v_I_ij (cos z_psi_ij)^2 + v_psi_ij (z_I_ij sin z_psi_ij)^2 \n v_Im(barI_ij) = v_I_ij (sin z_psi_ij)^2 + v_psi_ij (z_I_ij cos z_psi_ij)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The functions defining the current phasor measurement at the from-bus end are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barI_ij)(mathbf x) = (A_psi_ij cos theta_i - B_psi_ij sin theta_i)V_i - C_psi_ij cos (theta_j + phi_ij) - D_psi_ij sin (theta_j + phi_ij)V_j \n h_Im(barI_ij)(mathbf x) = (A_psi_ij sin theta_i + B_psi_ij cos theta_i)V_i - C_psi_ij sin (theta_j + phi_ij) + D_psi_ij cos (theta_j + phi_ij)V_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barI_ij)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial theta_i =\n -(A_psi_ij sin theta_i + B_psi_ij cos theta_i)V_i\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial theta_j =\n C_psi_ij sin(theta_j + phi_ij) + D_psi_ij cos(theta_j + phi_ij) V_j \n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial V_i =\n A_psi_ij cos theta_i - B_psi_ij sintheta_i\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial V_j =\n -C_psi_ij cos(theta_j + phi_ij) + D_psi_ij sin(theta_j + phi_ij)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barI_ij)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial theta_i =\n (A_psi_ij cos theta_i - B_psi_ij sin theta_i)V_i\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial theta_j =\n -C_psi_ij cos(theta_j + phi_ij) + D_psi_ij sin(theta_j + phi_ij) V_j \n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial V_i =\n A_psi_ij sin theta_i + B_psi_ij costheta_i\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial V_j =\n -C_psi_ij sin(theta_j + phi_ij) - D_psi_ij cos(theta_j + phi_ij)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barI_ij) w_Im(barI_ij)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₁₃, ψ₁₃\", from = 2, magnitude = 0.3, angle = -0.5,\nvarianceMagnitude = 1e-4, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barI_ij) = w_Im(barI_ij) = sin z_psi_ij cos z_psi_ij(v_I_ij - v_psi_ij z_I_ij^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-From-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Polar From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (I_ij psi_ij) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_I_ij z_psi_ij mathbfv_barmathcalP = v_I_ij v_psi_ij mathbfh_barmathcalP(mathbf x) = h_I_ij(mathbf x) h_psi_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₁₂, ψ₁₂\", from = 1, magnitude = 0.3, angle = -0.7,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-4, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function associated with the branch current magnitude at the from-bus end remains identical to the one provided in From-Bus End Current Magnitude Measurements. However, the function defining the branch current angle measurement is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_psi_ij(mathbf x) = mathrmatanBigg\n cfrac(A_psi_ij sintheta_i + B_psi_ij costheta_i)V_i - C_psi_ij sin(theta_j+phi_ij) + D_psi_ijcos(theta_j+phi_ij)V_j\n (A_psi_ij costheta_i - B_psi_ij sintheta_i)V_i - C_psi_ij cos(theta_j+phi_ij) - D_psi_ij sin(theta_j+phi_ij)V_j Bigg","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" A_psi_ij = cfracg_ij + g_textsitau_ij^2 B_psi_ij = cfracb_ij+b_textsitau_ij^2 \n C_psi_ij = cfracg_ijtau_ij D_psi_ij = cfracb_ijtau_ij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions associated with the branch current magnitude function h_I_ij(mathbf x) remains identical to the one provided in From-Bus End Current Magnitude Measurements. Further, Jacobian expressions corresponding to the measurement function h_psi_ij(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial theta_i =\n cfracA_I_ij V_i^2- C_I_ij cos(theta_ij- phi_ij) - D_I_ij sin (theta_ij - phi_ij) V_iV_jh_I_ij^2(mathbf x) \n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial theta_j =\n cfracB_I_ij V_j^2 - C_I_ij cos (theta_ij - phi_ij) - D_I_ij sin(theta_ij- phi_ij)V_iV_jh_I_ij^2(mathbf x) \n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial V_i = -\n cfracC_I_ij sin (theta_ij - phi_ij) + D_I_ij cos(theta_ij- phi_ij)V_j h_I_ij^2(mathbf x)\n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial V_j =\n cfracC_I_ij sin (theta_ij - phi_ij) + D_I_ij cos(theta_ij- phi_ij)V_i h_I_ij^2(mathbf x)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-To-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a PMU at branch (ij) in mathcalE, it can be placed at the to-bus end, denoted as (I_ji psi_ji) in barmathcalP, and it will be integrated into the AC state estimation model using rectangular coordinates by default. The user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barI_ji) z_Im(barI_ji) mathbfv_barmathcalP = v_Re(barI_ji) v_Im(barI_ji) mathbfh_barmathcalP(mathbf x) = h_Re(barI_ji)(mathbf x) h_Im(barI_ji)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₃₂, ψ₃₂\", to = 3, magnitude = 0.3, angle = -2.9,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barI_ji) = z_I_ji cos z_psi_ji\n z_Im(barI_ji) = z_I_ji sin z_psi_ji\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barI_ji) = v_I_ji (cos z_psi_ji)^2 + v_psi_ji (z_I_ji sin z_psi_ji)^2 \n v_Im(barI_ji) = v_I_ji (sin z_psi_ji)^2 + v_psi_ji (z_I_ji cos z_psi_ji)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The functions defining the current phasor measurement at the to-bus end are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barI_ji)(mathbf x) = (A_psi_ji cos theta_j - B_psi_ji sin theta_j)V_j - C_psi_ji cos (theta_i - phi_ij) - D_psi_ji sin (theta_i + phi_ij)V_i\n h_Im(barI_ji)(mathbf x) = (A_psi_ji sin theta_j + B_psi_ji cos theta_j)V_j - C_psi_ji sin (theta_i + phi_ij) + D_psi_ji cos (theta_i + phi_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barI_ji)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial theta_i =\n C_psi_ji sin (theta_i - phi_ij) + D_psi_ji cos (theta_i - phi_ij)V_i\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial theta_j =\n -(A_psi_ji sintheta_j + B_psi_ji cos theta_j ) V_j \n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial V_i =\n - C_psi_ji cos (theta_i - phi_ij) + D_psi_ji sin(theta_i - phi_ij)\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial V_j =\n A_psi_ji cos theta_j - B_psi_ji sin theta_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barI_ji)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial theta_i =\n -C_psi_ji cos (theta_i - phi_ij) + D_psi_ji sin (theta_i - phi_ij)V_i\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial theta_j =\n (A_psi_ji costheta_j - B_psi_ji sin theta_j ) V_j \n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial V_i =\n - C_psi_ji sin (theta_i - phi_ij) - D_psi_ji cos(theta_i - phi_ij)\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial V_j =\n A_psi_ji sin theta_j + B_psi_ji cos theta_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As before, we are neglecting the covariances between the real and imaginary parts of the measurement. If desired, we can include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barI_ji) w_Im(barI_ji)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₃₁, ψ₃₁\", to = 2, magnitude = 0.3, angle = 2.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barI_ji) = w_Im(barI_ji) = sin z_psi_ji cos z_psi_ji(v_I_ji - v_psi_ji z_I_ji^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-To-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Polar To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (I_ji psi_ji) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_I_ji z_psi_ji mathbfv_barmathcalP = v_I_ji v_psi_ji mathbfh_barmathcalP(mathbf x) = h_I_ji(mathbf x) h_psi_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₂₁, ψ₂₁\", to = 1, magnitude = 0.3, angle = 2.3,\nvarianceMagnitude = 1e-2, varianceAngle = 1e-3, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function associated with the branch current magnitude at the to-bus end remains identical to the one provided in To-Bus End Current Magnitude Measurements. However, the function defining the branch current angle measurement is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_psi_ji(mathbf x) = mathrmatanBigg\n cfrac(A_psi_ji sintheta_j + B_psi_ji costheta_j)V_j - C_psi_ji sin(theta_i-phi_ij) + D_psi_jicos(theta_i-phi_ij)V_i\n (A_psi_ji costheta_j - B_psi_ji sintheta_j)V_j - C_psi_ji cos(theta_i-phi_ij) - D_psi_ji sin(theta_i-phi_ij)V_i Bigg","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" A_psi_ji = g_ij + g_textsi B_psi_ji = b_ij + b_textsi \n C_psi_ji = cfracg_ijtau_ij D_psi_ji = cfracb_ijtau_ij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions associated with the branch current magnitude function h_I_ji(mathbf x) remains identical to the one provided in To-Bus End Current Magnitude Measurements. Further, Jacobian expressions corresponding to the measurement function h_psi_ji(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial theta_i =\n cfracA_I_ji V_i^2- C_I_ji cos(theta_ij- phi_ij) + D_I_ji sin (theta_ij - phi_ij) V_iV_jh_I_ji^2(mathbf x) \n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial theta_j =\n cfracB_I_ji V_j^2 - C_I_ji cos (theta_ij - phi_ij) + D_I_ji sin(theta_ij- phi_ij)V_iV_jh_I_ji^2(mathbf x) \n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial V_i =\n -cfracC_I_ji sin (theta_ij - phi_ij) - D_I_ji cos(theta_ij- phi_ij)V_j h_I_ji^2(mathbf x)\n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial V_j =\n cfracC_I_ji sin (theta_ij - phi_ij) - D_I_ji cos(theta_ij- phi_ij)V_i h_I_ji^2(mathbf x)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACSEWLSStateEstimationTutorials","page":"AC State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Given the available set of measurements mathcalM, the weighted least-squares estimator hatmathbf x, i.e., the solution of the weighted least-squares problem, can be found using the Gauss-Newton method:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tBigmathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf J (mathbf x^(nu))Big mathbf Delta mathbf x^(nu) =\n\t\tmathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf x^(nu+1) = mathbf x^(nu) + mathbf Delta mathbf x^(nu)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where nu = 012dots is the iteration index, mathbf Delta mathbf x in mathbb R^n_textu is the vector of increments of the state variables, mathbf J (mathbf x)in mathbb R^k times n_textu is the Jacobian matrix of measurement functions mathbf h (mathbf x) at mathbf x=mathbf x^(nu), bm Sigma in mathbb R^k times k is a measurement error covariance matrix, and mathbf r (mathbf x) = mathbfz - mathbf h (mathbf x) is the vector of residuals [13, Ch. 10]. It is worth noting that assuming uncorrelated measurement errors leads to a diagonal covariance matrix bm Sigma corresponding to measurement variances. However, when incorporating PMUs in a rectangular coordinate system and aiming to observe error correlation, this matrix loses its diagonal form.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The non-linear or AC state estimation represents a non-convex problem arising from the non-linear measurement functions [17]. Due to the fact that the values of state variables usually fluctuate in narrow boundaries, the non-linear model represents the mildly non-linear problem, where solutions are in a reasonable-sized neighborhood which enables the use of the Gauss-Newton method. The Gauss-Newton method can produce different rates of convergence, which can be anywhere from linear to quadratic [18, Sec. 9.2]. The convergence rate in regard to power system state estimation depends on the topology and measurements, and if parameters are consistent (e.g., free bad data measurement set), the method shows near quadratic convergence rate [13, Sec. 11.2].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Initialization","page":"AC State Estimation","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us begin by setting up a new set of measurements for the defined power system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device = measurement()\n\n@wattmeter(label = \"Watmeter ?\")\naddWattmeter!(system, device; bus = 3, active = -0.5, variance = 1e-3)\naddWattmeter!(system, device; from = 1, active = 0.2, variance = 1e-4)\n\n@varmeter(label = \"Varmeter ?\")\naddVarmeter!(system, device; bus = 2, reactive = -0.3, variance = 1e-3)\naddVarmeter!(system, device; from = 1, reactive = 0.2, variance = 1e-4)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = 1, magnitude = 1.0, angle = 0, polar = true)\naddPmu!(system, device; bus = 3, magnitude = 0.9, angle = -0.2)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To compute the voltage magnitudes and angles of buses using the Gauss-Newton method in JuliaGrid, we need to first execute the acModel! function to set up the system. Then, initialize the Gauss-Newton method using the gaussNewton function. The following code snippet demonstrates this process:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"acModel!(system)\nanalysis = gaussNewton(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Initially, the gaussNewton function constructs the mean vector holding measurement values:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, it forms the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. We can access these values using the following command:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, using initial bus voltage magnitudes and angles from the PowerSystem type, the function creates the starting vector mathbfx^(0) of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0) for the Gauss-Newton method:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we utilize a \"flat start\" approach in our method. It is important to keep in mind that when dealing with initial conditions in this manner, the Gauss-Newton method may encounter difficulties.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Iterative-Process","page":"AC State Estimation","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To apply the Gauss-Newton method, JuliaGrid provides the solve! function. This function is utilized iteratively until a stopping criterion is met, as demonstrated in the following code snippet:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function solve! calculates the vector of residuals at each iteration using the equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf r (mathbf x^(nu)) = mathbfz - mathbf h (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resulting vector from these calculations is stored in the residual variable of the ACStateEstimation type and can be accessed through the following line of code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐫 = analysis.method.residual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The order of the residual vector follows a specific pattern. If all device types exist, the first mathcalV elements correspond to voltmeters, followed by mathcalI elements corresponding to ammeters. Then we have mathcalP elements for wattmeters and mathcalQ elements for varmeters. Finally, we have 2barmathcalP elements for PMUs. The order of these elements within specific devices follows the same order as they appear in the input data defined by the Measurement type.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"At the same time, the function forms the Jacobian matrix mathbfJ (mathbfx^(nu)) and calculates the gain matrix mathbfG (mathbfx^(nu)) using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf G (mathbf x^(nu)) = mathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf J (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The Jacobian matrix and factorized gain matrix are stored in the ACStateEstimation type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐉 = analysis.method.jacobian\n𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then finally, the function computes the vector of state variable increments using the equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf Delta mathbf x^(nu) = mathbf G (mathbf x^(nu))^-1 mathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing the gain matrix mathbfG = mathbfLmathbfU, aiming to compute the increments. Nevertheless, users have the flexibility to opt for QR or LDLt factorization as an alternative method.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Increment values are stored in the ACStateEstimation type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝚫𝐱 = analysis.method.increment","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here again, the JuliaGrid implementation of the AC state estimation follows a specific order to store the increment vector and Jacobian matrix. The vector of increments first contains n increments of bus voltage angles mathbf Delta bmTheta, followed by n increments of bus voltage magnitudes mathbf Delta mathbfV. This order also corresponds to the columns of the Jacobian matrix, while the order of rows of the Jacobian is defined according to the order of the residual vector.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Note that the increment vector and Jacobian matrix hold the slack bus with a known voltage angle. An element of the increment vector and a column of the Jacobian matrix are not deleted, and the presence on the slack bus is handled internally by JuliaGrid, which is evident from the factorization of the gain matrix.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function solve! adds the computed increment term to the previous solution to obtain a new solution:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf x^(nu + 1) = mathbf x^(nu) + mathbf Delta mathbf x^(nu)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, the bus voltage magnitudes mathbfV = V_i and angles bmTheta = theta_i are stored in the following vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, the solve! function provides the maximum absolute value of state variable increments, typically employed as the termination criterion for the iteration loop. Specifically, if it falls below a predefined stopping criterion epsilon, the algorithm converges:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" max Delta x_i forall i epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Jacobian-Matrix","page":"AC State Estimation","title":"Jacobian Matrix","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a reminder, the Jacobian matrix consists of n columns representing bus voltage angles bmTheta, followed by n columns representing bus voltage magnitudes mathbfV. The arrangement of rows is structured such that the first mathcalV rows correspond to voltmeters, followed by mathcalI rows corresponding to ammeters. Then, we have mathcalP rows for wattmeters and mathcalQ rows for varmeters. Finally, there are 2barmathcalP rows for PMUs. The elements are computed based on the provided Jacobian expressions.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Precision-Matrix","page":"AC State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us revisit the precision matrix mathbf W. In the previous example, we introduced a PMU in rectangular coordinates without considering correlations between measurement errors. Now, let us update that PMU to include correlation between measurement errors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device, analysis; label = \"PMU 2\", correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we can examine the updated precision matrix mathbf W:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Observing the precision matrix, we notice that it loses its diagonal form due to the inclusion of measurement covariances in the model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Alternative-Formulation","page":"AC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device; label = \"PMU 2\", correlated = false)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can now employ the orthogonal factorization approach:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device, Orthogonal)\n\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t Bigmathbf J (mathbf x^(nu))^T mathbf W mathbf J (mathbf x^(nu))Big mathbf Delta mathbf x^(nu) =\n\t\tmathbf J (mathbf x^(nu))^T mathbf W mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" leftmathbf W^12 mathbf J (mathbf x^(nu))right^T mathbf W^12 mathbf J (mathbf x^(nu)) Delta mathbf x^(nu) =\n leftmathbf W^12 mathbf J (mathbf x^(nu))right^T mathbf W^12 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu))^T barmathbf J(mathbf x^(nu)) Delta mathbf x^(nu) = barmathbf J(mathbf x^(nu))^T barmathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu)) = mathbf W^12 mathbf J (mathbf x^(nu)) barmathbf r (mathbf x^(nu)) = mathbf W^12 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, within each iteration of the Gauss-Newton method, JuliaGrid conducts QR factorization on the rectangular matrix:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu)) = mathbf W^12 mathbf J (mathbf x^(nu)) = mathbfQmathbfR","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the solution, JuliaGrid avoids explicitly forming the orthogonal matrix mathbfQ. Once the algorithm converges, estimates of bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, where i in mathcalN can be accessed using variables:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACBadDataTutorials","page":"AC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; bus = 3, active = 5.1, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we will construct the AC state estimation model and solve it:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" r_i = z_i - h_i(hat mathbf x) i in mathcalM","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf J (hat mathbf x) mathbf J (hat mathbf x)^T bm Sigma^-1 mathbf J (hat mathbf x)^-1 mathbf J (hat mathbf x)^T","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"is removed from the measurement set and marked as out-of-service.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we can solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACLAVTutorials","page":"AC State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This section outlines the method as described in [5, Sec. 6.5]. Hence, we consider the system of nonlinear equations:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz=mathbfh(mathbf x)+mathbfu","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n textminimize sum_i in mathcalM r_i\n textsubjectto z_i - h_i(mathbf x) = r_i forall i in mathcalM\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where r_i represents the i-th measurement residual. Let eta_i be defined in a manner that ensures:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" r_i leq eta_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"and replace the above inequality with two equalities using two non-negative slack variables q_i and w_i:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i - q_i = -eta_i \n r_i + w_i = eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us now define two additional non-negative variables overliner_i and underliner_i, which satisfy the following relationships:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i = overliner_i - underliner_i\n overliner_i = cfrac12 q_i \n underliner_i = cfrac12 w_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i - 2overliner_i = -2 eta_i \n r_i + 2 underliner_i = 2 eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"that is:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n overliner_i + underliner_i = eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, we define a vector of state variables according to two additional nonnegative vectors overlinemathbf x in mathbb R_ge 0^n_textu and underlinemathbf x in mathbb R_ge 0^n_textu, which satisfy the following relationships:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf x = overlinemathbf x - underlinemathbf x","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n textminimize sum_i in mathcalM (overliner_i + underliner_i) \n textsubjectto h_i(overlinemathbf x - underlinemathbf x) + overliner_i - underliner_i = z_i forall i in mathcalM \n overliner_i geq 0 underliner_i geq 0 forall i in mathcalM \n overlinemathbf x succeq mathbf 0 underlinemathbf x succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, we obtain optimal values for the four non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" hatmathbf x = overlinemathbf x - underlinemathbf x","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can retrieve the estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACObservabilityAnalysisTutorials","page":"AC State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The state estimation algorithm aims to estimate the values of the state variables based on the measurement model described as a system of equations. Prior to applying the state estimation algorithm, the observability analysis determines the existence and uniqueness of the solution for the underlying system of equations. In cases where a unique solution is not guaranteed, the observability analysis identifies observable islands and prescribes an additional set of equations (pseudo-measurements) to achieve a unique solution [20].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Identification-of-Observable-Islands","page":"AC State Estimation","title":"Identification of Observable Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid employs standard observability analysis performed on the linear decoupled measurement model [13, Ch. 7]. Active power measurements from wattmeters are utilized to estimate bus voltage angles, while reactive power measurements from varmeters are used to estimate bus voltage magnitudes. This necessitates that measurements of active and reactive power come in pairs.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us illustrate this concept with the following example, where measurements form an unobservable system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.5, reactive = 0.01)\naddBus!(system; label = \"Bus 4\", type = 1, active = 0.2, reactive = 0.02)\naddBus!(system; label = \"Bus 5\", type = 1, active = 0.3, reactive = 0.03)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.002)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 4\", reactance = 0.02)\naddBranch!(system; label = \"Branch 4\", from = \"Bus 3\", to = \"Bus 4\", reactance = 0.03)\naddBranch!(system; label = \"Branch 5\", from = \"Bus 4\", to = \"Bus 5\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 4.2, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", active = 0.2, reactive = 0.1)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 0.93)\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = -0.41)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", bus = \"Bus 2\", active = -0.1)\naddVarmeter!(system, device; label = \"Varmeter 2\", bus = \"Bus 2\", reactive = -0.01)\n\naddWattmeter!(system, device; label = \"Wattmeter 3\", bus = \"Bus 3\", active = -0.30)\naddVarmeter!(system, device; label = \"Varmeter 3\", bus = \"Bus 3\", reactive = 0.52)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the system lacks observability, the observability analysis needs to identify all potential observable islands that can be independently solved. An observable island is defined as follows: It is a segment of the power system where the flows across all branches within that island can be calculated solely from the available measurements. This independence holds regardless of the values chosen for the bus voltage angle at the slack bus [13, Sec. 7.1.1]. Within this context, two types of observable islands are evident:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"flow observale islands,\nmaximal observable islands.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The selection between them relies on the power system's structure and the available measurements. Opting for detecting only flow observable islands simplifies the island detection function's complexity but increases the complexity in the restoration function compared to identifying maximal observable islands.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Flow-Observale-Islands","page":"AC State Estimation","title":"Flow Observale Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To identify flow observable islands, JuliaGrid employs a topological method outlined in [21]. The process begins with the examination of all active power flow measurements from wattmeters, aiming to determine the largest sets of connected buses within the network linked by branches with active power flow measurements. Subsequently, the analysis considers individual boundary or tie active power injection measurements, involving two islands that may potentially be merged into a single observable island. The user can initiate this process by calling the function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopologicalFlow(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, four flow observable islands are identified. The first island comprises Bus 1 and Bus 2, while the second, third, and fourth islands consist of Bus 3, Bus 4, and Bus 5, respectively:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, users can inspect the tie buses and branches resulting from the observability analysis we conducted:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.tie.bus\nislands.tie.branch","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This tie data will be utilized throughout the restoration step, where we introduce pseudo-measurements to merge the observable flow islands obtained.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Maximal-Observale-Islands","page":"AC State Estimation","title":"Maximal Observale Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To identify maximal observable islands, we extend the analysis with an additional processing step. After processing individual injection tie measurements, we are left with a series of injection measurements that are not entirely contained within any observable zone. In this set of remaining tie injections, we now examine pairs involving three and only three previously determined observable zones (including individual buses). If we find such a pair, the three islands may be merged, and all injection measurements involving only nodes of this new island are excluded from further consideration. The procedure then restarts at the stage where we process tie active power injection measurements involving two and only two islands. If no mergers are possible with pairs, we then consider sets of three injection measurements involving four islands, and so on [21]. The user can initiate this by calling the function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome reveals the identification of two maximal observable islands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is evident that upon comparing this result with the flow islands, the merging of the two injection measurements at Bus 2 and Bus 3 consolidated the first, second, and third flow observable islands into a single island.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here we can observe tie data:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.tie.bus\nislands.tie.branch","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Compared to the tie data obtained after detecting flow observable islands, we now have a smaller set, indicating that the restoration step will be more computationally efficient.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Observability-Restoration","page":"AC State Estimation","title":"Observability Restoration","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Before commencing the restoration of observability in the context of the linear decoupled measurement model and observability analysis, it is imperative to ensure that the system possesses one bus voltage magnitude measurement. This necessity arises from the fact that observable islands are identified based on wattmeters, where wattmeters are tasked with estimating voltage angles. Since one voltage angle is already known from the slack bus, the same principle should be applied to bus voltage magnitudes. Therefore, to address this requirement, we add:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After determining the islands, the observability analysis merges these islands in a manner that protect previously determined observable states from being altered by the new set of equations defined by the additional measurements, called pseudo-measurements. In general, this can be achieved by ensuring that the set of new measurements forms a non-redundant set [13, Sec. 7.3.2], i.e., the set of equations must be linearly independent with respect to the global system. The goal of observability restoration is to find this non-redundant set.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome of the island detection step results in the power system being divided into m islands. Subsequently, we focus on the set of measurements mathcalM_textr subset mathcalM, which exclusively consists of:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active power injection measurements at tie buses,\nbus voltage phasor measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These measurements are retained from the phase where we identify observable islands, and are crucial in determining whether we need additional pseudo-measurements to be included in the measurement set mathcalM. In this specific example, we do not have active power injection measurements at tie buses remaining after the identification of maximal observable islands. However, if we proceed with flow observable islands to the restoration step, we will have two injection measurements at Bus 2 and Bus 3.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"However, let us introduce the matrix mathbf M_textr in mathbbR^r times m, where r = mathcalM_textr. This matrix can be conceptualized as the coefficient matrix of a reduced network, with m columns corresponding to islands and r rows associated with the set mathcalM_textr. More precisely, if we construct the coefficient matrix mathbf H_textr linked to the set mathcalM_textr in the DC framework, the matrix mathbf M_textr can be constructed by summing the columns of mathbf H_textr that belong to a specific island [22].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user needs to establish a set of pseudo-measurements, where measurements must come in pairs as well. Let us create that set:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"pseudo = measurement()\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 1\", bus = \"Bus 1\", active = 0.93)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 1\", bus = \"Bus 1\", reactive = -0.41)\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 2\", from = \"Branch 5\", active = 0.30)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 2\", from = \"Branch 5\", reactive = 0.03)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"From this set, the restoration step will only utilize the following:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active power flow measurements between tie buses,\nactive power injection measurements at tie buses,\nbus voltage phasor measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These pseudo-measurements mathcalM_textp will define the reduced coefficient matrix mathbf M_textp in mathbbR^p times m, where p = mathcalM_textp. In the current example, only Pseudo-Wattmeter 2 will contribute to the construction of the matrix mathbf M_textp. Similar to the previous case, measurement functions linked to the set mathcalM_textp define the coefficient matrix mathbf H_textp, and the matrix mathbf M_textp can be viewed as the sum of the columns of mathbf H_textp belonging to a specific flow island.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, users have the option to include bus voltage angle measurements from PMUs. In this scenario, restoration can be conducted without merging observable islands into one island, as each island becomes globally observable when one angle is known. It is important to note that during the restoration step, JuliaGrid initially processes active power measurements and subsequently handles bus voltage angle measurements if they are present in the set of pseudo-measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can execute the observability restoration procedure with the following:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"restorationGram!(system, device, pseudo, islands; threshold = 1e-6)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function constructs the reduced coefficient matrix as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf M = beginbmatrix mathbf M_textr mathbf M_textp endbmatrix","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"and forms the corresponding Gram matrix:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf D = mathbf M mathbf M^T","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The decomposition of mathbf D into its mathbf Q and mathbf R factors is achieved through QR factorization. Non-redundant measurements are identified by non-zero diagonal elements in mathbf R. Specifically, if the diagonal element satisfies:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" R_ii epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid designates the corresponding measurement as redundant, where epsilon represents a pre-determined zero pivot threshold, set to 1e-6 in this example. The minimal set of pseudo-measurements for observability restoration corresponds to the non-zero diagonal elements at positions associated with the candidate pseudo-measurements. It is essential to note that an inappropriate choice of the zero pivot threshold may adversely affect observability restoration. Additionally, there is a possibility that the set of pseudo-measurements mathcalM_textp may not be sufficient for achieving observability restoration.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, the Pseudo-Wattmeter 2, and consequently Pseudo-Varmeter 2 measurements successfully restore observability, and these measurements are added to the device variable, which stores actual measurements:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device.wattmeter.label\ndevice.varmeter.label","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we can confirm that the new measurement set establishes the observable system formed by a single island:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device);\n\nislands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, we can construct the AC state estimation model and resolve it to obtain estimates of bus voltages:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACPowerAnalysisTutorials","page":"AC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-Injections","page":"AC State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACGeneratorPowerInjectionsManual","page":"AC State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can calculate the active and reactive power injections supplied by generators at each bus i in mathcalN by summing the active and reactive power injections and the active and reactive power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n P_textpi = P_i + P_textdi\n Q_textpi = Q_i + Q_textdi\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The active and reactive power injections from the generators at each bus are stored as vectors, denoted by mathbfP_textp = P_textpi and mathbfQ_textp = Q_textpi, which can be obtained using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₚ = analysis.power.supply.active\n𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Bus-Shunt-Elements","page":"AC State Estimation","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-Flows","page":"AC State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Branch-Shunt-Elements","page":"AC State Estimation","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Branch-Series-Elements","page":"AC State Estimation","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#PMUCurrentAnalysisTutorials","page":"AC State Estimation","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-Injections","page":"AC State Estimation","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-Flows","page":"AC State Estimation","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-at-Branch-Series-Elements","page":"AC State Estimation","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/powerSystemModel/#powerSystemModelAPI","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For further information on this topic, please see the Power System Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate power system structures, as well as to build AC and DC models of power systems.","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Power-System","page":"Power System Model","title":"Power System","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem\nsavePowerSystem\nacModel!\ndcModel!","category":"page"},{"location":"api/powerSystemModel/#Bus","page":"Power System Model","title":"Bus","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!\nupdateBus!\n@bus","category":"page"},{"location":"api/powerSystemModel/#Branch","page":"Power System Model","title":"Branch","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBranch!\nupdateBranch!\n@branch","category":"page"},{"location":"api/powerSystemModel/#Generator","page":"Power System Model","title":"Generator","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addGenerator!\nupdateGenerator!\ncost!\n@generator","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Power-System-2","page":"Power System Model","title":"Power System","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem\nsavePowerSystem\nacModel!\ndcModel!","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.powerSystem","page":"Power System Model","title":"JuliaGrid.powerSystem","text":"powerSystem(file::String)\n\nThe function builds the composite type PowerSystem and populates bus, branch, generator and base fields. Once the composite type PowerSystem has been created, it is possible to add new buses, branches, or generators, or modify the parameters of existing ones.\n\nArgument\n\nIt requires a string path to:\n\nthe HDF5 file with the .h5 extension,\nthe Matpower file with the .m extension.\n\nReturns\n\nThe PowerSystem composite type with the following fields:\n\nbus: Data related to buses.\nbranch: Data related to branches.\ngenerator: Data related to generators.\nbase: Base power and base voltages.\nmodel: Data associated with AC and DC analyses.\n\nUnits\n\nJuliaGrid stores all data in per-units and radians format which are fixed, the exceptions are base values in volt-amperes and volts. The prefixes for these base values can be changed using the @base macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\n\n\n\n\npowerSystem()\n\nAlternatively, the PowerSystem composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed. This generates an empty PowerSystem type, with only the base power initialized to 1.0e8 volt-amperes (VA).\n\nExample\n\nsystem = powerSystem()\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.savePowerSystem","page":"Power System Model","title":"JuliaGrid.savePowerSystem","text":"savePowerSystem(system::PowerSystem; path::String, reference::String, note::String)\n\nThe function saves the power system's data in the HDF5 file using the fields bus, branch, generator, and base from the PowerSystem composite type.\n\nKeywords\n\nThe location and file name of the HDF5 file is specified by the mandatory keyword path in the format of \"path/name.h5\". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.\n\nView HDF5 File\n\nTo view the saved HDF5 file, you can use the HDFView software.\n\nExample\n\nsystem = powerSystem(\"case14.m\")\nsavePowerSystem(system; path = \"D:/case14.h5\")\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.acModel!","page":"Power System Model","title":"JuliaGrid.acModel!","text":"acModel!(system::PowerSystem)\n\nThe function generates vectors and matrices based on the power system topology and parameters associated with AC analyses.\n\nUpdates\n\nThe function updates the model.ac field within the PowerSystem composite type, populating the following variables:\n\nnodalMatrix: The nodal matrix.\nnodalMatrixTranspose: The transpose of the nodal matrix.\nnodalFromFrom: The Y-parameters of the two-port branches.\nnodalFromTo: The Y-parameters of the two-port branches.\nnodalToTo: The Y-parameters of the two-port branches.\nnodalToFrom: The Y-parameters of the two-port branches.\nadmittance: The branch admittances.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.dcModel!","page":"Power System Model","title":"JuliaGrid.dcModel!","text":"dcModel!(system::PowerSystem)\n\nThe function generates vectors and matrices based on the power system topology and parameters associated with DC analyses.\n\nUpdates\n\nThe function updates the model.dc field within the PowerSystem composite type, populating the following variables:\n\nnodalMatrix: The nodal matrix.\nadmittance: The branch admittances.\nshiftPower: The active powers related to phase-shifting transformers.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Bus-2","page":"Power System Model","title":"Bus","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!\nupdateBus!\n@bus","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addBus!","page":"Power System Model","title":"JuliaGrid.addBus!","text":"addBus!(system::PowerSystem; label, type, active, reactive, conductance, susceptance,\n magnitude, angle, minMagnitude, maxMagnitude, base, area, lossZone)\n\nThe function adds a new bus to the PowerSystem composite type.\n\nKeywords\n\nThe bus is defined with the following keywords:\n\nlabel: Unique label for the bus.\ntype: Bus type:\ntype = 1: demand bus (PQ),\ntype = 2: generator bus (PV),\ntype = 3: slack bus (Vθ).\nactive (pu or W): Active power demand at the bus.\nreactive (pu or VAr): Reactive power demand at the bus.\nconductance (pu or W): Active power demanded of the shunt element.\nsusceptance (pu or VAr): Reactive power injected/demanded of the shunt element.\nmagnitude (pu or V): Initial value of the bus voltage magnitude.\nangle (rad or deg): Initial value of the bus voltage angle.\nminMagnitude (pu or V): Minimum bus voltage magnitude value.\nmaxMagnitude (pu or V): Maximum bus voltage magnitude value.\nbase (V): Voltage base value.\narea: Area number.\nlossZone: Loss zone.\n\nUpdates\n\nThe function updates the bus field of the PowerSystem composite type.\n\nDefault Settings\n\nThe default settings for certain keywords are as follows: type = 1, magnitude = 1.0, minMagnitude = 0.9, maxMagnitude = 1.1, and base = 138e3. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @bus macro.\n\nUnits\n\nBy default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.\n\nExamples\n\nAdding a bus using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 0.25, angle = 0.175, base = 132e3)\n\nAdding a bus using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 25.0, angle = 10.026, base = 132.0)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateBus!","page":"Power System Model","title":"JuliaGrid.updateBus!","text":"updateBus!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing bus.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific bus, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBus! function, along with their respective values. Ensure that the label keyword matches the label of the existing bus you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the bus field within the PowerSystem composite type, and in cases where parameters impact variables in the ac field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBus! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\nupdateBus!(system; label = \"Bus 1\", active = 0.15, susceptance = 0.15)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@bus","page":"Power System Model","title":"JuliaGrid.@bus","text":"@bus(kwargs...)\n\nThe macro generates a template for a bus, which can be utilized to define a bus using the addBus! function.\n\nKeywords\n\nTo define the bus template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBus! function, along with their corresponding values.\n\nUnits\n\nBy default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.\n\nExamples\n\nAdding a bus template using the default unit system:\n\nsystem = powerSystem()\n\n@bus(type = 2, active = 0.25, angle = 0.1745)\naddBus!(system; label = \"Bus 1\", reactive = -0.04, base = 132e3)\n\nAdding a bus template using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\n@bus(type = 2, active = 25.0, angle = 10.0, base = 132.0)\naddBus!(system; label = \"Bus 1\", reactive = -4.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Branch-2","page":"Power System Model","title":"Branch","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBranch!\nupdateBranch!\n@branch","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addBranch!","page":"Power System Model","title":"JuliaGrid.addBranch!","text":"addBranch!(system::PowerSystem, [analysis::Analysis]; label, from, to, status,\n resistance, reactance, conductance, susceptance, turnsRatio, shiftAngle,\n minDiffAngle, maxDiffAngle, minFromBus, maxFromBus, minToBus, maxToBus, type)\n\nThe function adds a new branch to the PowerSystem composite type. A branch can be added between already defined buses.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.\n\nKeywords\n\nThe branch is defined with the following keywords:\n\nlabel: Unique label for the branch.\nfrom: From-bus label, corresponds to the bus label.\nto: To-bus label, corresponds to the bus label.\nstatus: Operating status of the branch:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\nresistance (pu or Ω): Series resistance.\nreactance (pu or Ω): Series reactance.\nconductance (pu or S): Total shunt conductance.\nsusceptance (pu or S): Total shunt susceptance.\nturnsRatio: Transformer off-nominal turns ratio, equal to one for a line.\nshiftAngle (rad or deg): Transformer phase shift angle, where positive value defines delay.\nminDiffAngle (rad or deg): Minimum voltage angle difference value between from-bus and to-bus ends.\nmaxDiffAngle (rad or deg): Maximum voltage angle difference value between from-bus and to-bus ends.\nminFromBus (pu, VA, W, or A): Minimum branch flow rating at the from-bus end.\nmaxFromBus (pu, VA, W, or A): Maximum branch flow rating at the from-bus end.\nminToBus (pu, VA, W, or A): Minimum branch flow rating at the to-bus end.\nmaxToBus (pu, VA, W, or A): Maximum branch flow rating at the to-bus end.\ntype: Types of minFromBus, maxFromBus, minToBus, and maxToBus branch flow ratings:\ntype = 1: apparent power flow (pu or VA),\ntype = 2: active power flow (pu or W),\ntype = 3: current magnitude flow (pu or A).\n\nUpdates\n\nThe function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nDefault Settings\n\nBy default, certain keywords are assigned default values: status = 1, turnsRatio = 1.0, type = 1, minDiffAngle = -2pi, and maxDiffAngle = 2pi. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @branch macro.\n\nUnits\n\nThe default units for the keyword parameters are per-units (pu) and radians (rad). However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, @current, and @parameter.\n\nExamples\n\nAdding a branch using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\n\nAdding a branch using a custom unit system:\n\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateBranch!","page":"Power System Model","title":"JuliaGrid.updateBranch!","text":"updateBranch!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing branch.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter\n\nKeywords\n\nTo update a specific branch, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBranch! function, along with their respective values. Ensure that the label keyword matches the label of the existing branch you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBranch! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\nupdateBranch!(system; label = \"Branch 1\", reactance = 0.02, susceptance = 0.062)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@branch","page":"Power System Model","title":"JuliaGrid.@branch","text":"@branch(kwargs...)\n\nThe macro generates a template for a branch, which can be utilized to define a branch using the addBranch! function.\n\nKeywords\n\nTo define the branch template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBranch! function, along with their corresponding values.\n\nUnits\n\nThe default units for the keyword parameters are per-units and radians. However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, and @parameter.\n\nExamples\n\nAdding a branch template using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\n@branch(reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\")\n\nAdding a branch template using a custom unit system:\n\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\n@branch(shiftAngle = 10)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n\n\n\n\n","category":"macro"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Generator-2","page":"Power System Model","title":"Generator","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addGenerator!\nupdateGenerator!\ncost!\n@generator","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addGenerator!","page":"Power System Model","title":"JuliaGrid.addGenerator!","text":"addGenerator!(system::PowerSystem, [analysis::Analysis]; label, bus, status,\n active, reactive, magnitude, minActive, maxActive, minReactive, maxReactive,\n lowActive, minLowReactive, maxLowReactive, upActive, minUpReactive, maxUpReactive,\n loadFollowing, reactiveRamp, reserve10min, reserve30min, area)\n\nThe function adds a new generator to the PowerSystem composite type. The generator can be added to an already defined bus.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new generator.\n\nKeywords\n\nThe generator is defined with the following keywords:\n\nlabel: Unique label for the generator.\nbus: Label of the bus to which the generator is connected.\nstatus: Operating status of the generator:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\nactive (pu or W): Output active power.\nreactive (pu or VAr): Output reactive power.\nmagnitude (pu or V): Voltage magnitude setpoint.\nminActive (pu or W): Minimum allowed output active power value.\nmaxActive (pu or W): Maximum allowed output active power value.\nminReactive (pu or VAr): Minimum allowed output reactive power value.\nmaxReactive (pu or VAr): Maximum allowed output reactive power value.\nlowActive (pu or W): Lower allowed active power output value of PQ capability curve.\nminLowReactive (pu or VAr): Minimum allowed reactive power output value at lowActive value.\nmaxLowReactive (pu or VAr): Maximum allowed reactive power output value at lowActive value.\nupActive (pu or W): Upper allowed active power output value of PQ capability curve.\nminUpReactive (pu or VAr): Minimum allowed reactive power output value at upActive value.\nmaxUpReactive (pu or VAr): Maximum allowed reactive power output value at upActive value.\nloadFollowing (pu/min or W/min): Ramp rate for load following/AG.\nreserve10min (pu or W): Ramp rate for 10-minute reserves.\nreserve30min (pu or W): Ramp rate for 30-minute reserves.\nreactiveRamp (pu/min or VAr/min): Ramp rate for reactive power, two seconds timescale.\narea: Area participation factor.\n\nUpdates\n\nThe function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nDefault Settings\n\nBy default, certain keywords are assigned default values: status = 1 and magnitude = 1.0 per-unit. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @generator macro.\n\nUnits\n\nBy default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.\n\nExamples\n\nAdding a generator using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.2, base = 132e3)\n\naddGenerator!(system; bus = \"Bus 1\", active = 0.5, magnitude = 1.1)\n\nAdding a generator using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(kV, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 20, base = 132)\n\naddGenerator!(system; bus = \"Bus 1\", active = 50, magnitude = 145.2)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateGenerator!","page":"Power System Model","title":"JuliaGrid.updateGenerator!","text":"updateGenerator!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing generator.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter\n\nKeywords\n\nTo update a specific generator, provide the necessary kwargs input arguments in accordance with the keywords specified in the addGenerator! function, along with their respective values. Ensure that the label keyword matches the label of the existing generator you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBranch! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.2, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\nupdateGenerator!(system; label = \"Generator 1\", active = 0.6, reactive = 0.2)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.cost!","page":"Power System Model","title":"JuliaGrid.cost!","text":"cost!(system::PowerSystem, [analysis::Analysis]; label, active, reactive,\n piecewise, polynomial)\n\nThe function either adds a new cost or modifies an existing one for the active or reactive power generated by the corresponding generator within the PowerSystem composite type. It has the capability to append a cost to an already defined generator.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.\n\nKeywords\n\nThe function accepts five keywords:\n\nlabel: Corresponds to the already defined generator label.\nactive: Active power cost model:\nactive = 1: adding or updating cost, and piecewise linear is being used,\nactive = 2: adding or updating cost, and polynomial is being used.\nreactive: Reactive power cost model:\nreactive = 1: adding or updating cost, and piecewise linear is being used,\nreactive = 2: adding or updating cost, and polynomial is being used.\npiecewise: Cost model defined by input-output points given as Matrix{Float64}:\nfirst column (pu, W or VAr): active or reactive power output of the generator,\nsecond column (€/hr): cost for the specified active or reactive power output.\npolynomial: The n-th degree polynomial coefficients given as Vector{Float64}:\nfirst element (€/puⁿ-hr, €/Wⁿhr or €/VArⁿ-hr): coefficient of the n-th degree term, ....,\npenultimate element (€/pu-hr, €/W-hr or €/VAr-hr): coefficient of the first degree term,\nlast element (€/hr): constant coefficient.\n\nUpdates\n\nThe function updates the generator.cost field within the PowerSystem composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nBy default, the input units related with active powers are per-units (pu), but they can be modified using the macro @power.\n\nExamples\n\nAdding a cost using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 0.25, reactive = -0.04, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.0; 500.0; 150.0])\n\nAdding a cost using a custom unit system:\n\n@power(MW, MVAr, MVA)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 25, reactive = -4, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 50, reactive = 10)\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [0.11; 5.0; 150.0])\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@generator","page":"Power System Model","title":"JuliaGrid.@generator","text":"@generator(kwargs...)\n\nThe macro generates a template for a generator, which can be utilized to define a generator using the addGenerator! function.\n\nKeywords\n\nTo define the generator template, the kwargs input arguments must be provided in accordance with the keywords specified within the addGenerator! function, along with their corresponding values.\n\nUnits\n\nBy default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.\n\nExamples\n\nAdding a generator using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.25, reactive = -0.04, base = 132e3)\n\n@generator(magnitude = 1.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5, reactive = 0.1)\n\nAdding a generator using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(kV, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 25, reactive = -4, base = 132)\n\n@generator(magnitude = 145.2)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 50, reactive = 10)\n\n\n\n\n\n","category":"macro"},{"location":"tutorials/dcPowerFlow/#DCPowerFlowTutorials","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid employs standard network components and the Unified Branch Model to obtain the DC power flow solution. To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7)\naddBus!(system; label = 3, type = 2, conductance = 0.07)\n\naddBranch!(system; from = 1, to = 2, reactance = 0.26)\naddBranch!(system; from = 1, to = 3, reactance = 0.38)\naddBranch!(system; from = 2, to = 3, reactance = 0.17, turnsRatio = 0.97)\n\naddGenerator!(system; bus = 1, active = 2.0)\naddGenerator!(system; bus = 1, active = 4.0)\naddGenerator!(system; bus = 3, active = 5.0)\nnothing #hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element associated with bus i in mathcalN, and a_ij represents the element associated with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#DCPowerFlowSolutionTutorials","page":"DC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"As discussed in section DC Model, the DC power flow problem can be represented by a set of linear equations:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" mathbf P = mathbfB bm Theta + mathbfP_texttr + mathbfP_textsh","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Implementation","page":"DC Power Flow","title":"Implementation","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid offers a set of functions to solve the DC power flow problem and obtain the bus voltage angles. Firstly, the power system is loaded and the DC model is built using the following code sequence:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The DC power flow solution is obtained through a non-iterative approach by solving the system of linear equations:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" bm Theta = mathbfB^-1(mathbf P - mathbfP_texttr - mathbfP_textsh)","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid begins the process by establishing the DC power flow framework:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"analysis = dcPowerFlow(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The subsequent step involves performing the LU factorization of the nodal matrix mathbfB = mathbfLmathbfU and computing the bus voltage angles using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the nodal matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The factorization of the nodal matrix can be accessed using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"It is important to note that the slack bus voltage angle is excluded from the vector bmTheta only during the computation step. Consequently, the corresponding elements in the vectors mathbf P, mathbfP_texttr, mathbfP_textsh, and the corresponding row and column of the matrix mathbfB are removed. It is worth mentioning that this process is handled internally, and the stored elements remain unchanged.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, the resulting bus voltage angles are saved in the vector as follows:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#DCPowerAnalysisTutorials","page":"DC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution from the DC power flow, we can calculate powers related to buses, branches, and generators using the power! function:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Power-Injections","page":"DC Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Generator-Power-Injections","page":"DC Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The active power supplied by generators to the buses can be calculated by summing the given generator active powers in the input data, except for the slack bus, which can be determined as:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" P_textpi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"where P_textdi represents the active power demanded by consumers at the slack bus. The vector of active powers injected by generators into the buses, denoted by mathbfP_textp = P_textpi, can be obtained using the following command:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Power-Flows","page":"DC Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The resulting from-bus active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Similarly, the resulting to-bus active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Generators-Power-Outputs","page":"DC Power Flow","title":"Generators Power Outputs","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The output active power of each generator located at bus i in mathcalN_textpv cup mathcalN_textpq is equal to the active power specified in the input data. If there are multiple generators, their output active powers are also equal to the active powers specified in the input data. However, the output active power of a generator located at the slack bus will be:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" P_textgi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In the case of multiple generators connected to the slack bus, the first generator in the input data is assigned the obtained value of P_textgi. Then, this amount of power is reduced by the output active power of the other generators.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To retrieve the vector of active power outputs of generators, denoted as mathbfP_textg = P_textgi, i in mathcalS, where the set mathcalS represents the set of generators, users can utilize the following command:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowTutorials","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, Ipopt\n@default(unit) # hide\n@default(template) # hide\n\n@labels(Integer)\n\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.95, maxMagnitude = 1.05)\naddBus!(system; label = 1, type = 3, active = 0.1, angle = -0.1)\naddBus!(system; label = 2, reactive = 0.01, magnitude = 1.1)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, reactance = 0.5, type = 2)\naddBranch!(system; label = 1, from = 1, to = 2, maxFromBus = 0.15, maxToBus = 0.15)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1)\naddGenerator!(system; label = 1, bus = 1, active = 0.4, reactive = 0.2)\naddGenerator!(system; label = 2, bus = 2, active = 0.2, reactive = 0.1)\n\ncost!(system; label = 1, active = 2, polynomial = [900.0; 500.0; 80.0; 5.0])\ncost!(system; label = 2, active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\ncost!(system; label = 1, reactive = 1, piecewise = [10.0 20.0; 20.0 40.0])\ncost!(system; label = 2, reactive = 2, polynomial = [2.0])\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Moreover, we identify the set of generators as mathcalS = 1 dots n_textg within the power system:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝒮 = collect(keys(system.generator.label))","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or generator i in mathcalS, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowModelTutorials","page":"AC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow model, the active and reactive power outputs of the generators, denoted as mathbf P_textg = P_textgi and mathbf Q_textg = Q_textgi, where i in mathcalS, are expressed as nonlinear functions of the bus voltage magnitudes and angles, denoted as mathbf V = V_i and bmTheta = theta_i, where i in mathcalN. Consequently, the optimization variables encompass the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The AC optimal power flow problem can be formulated as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n textminimize sum_i in mathcalS left f_i(P_textgi) + f_i(Q_textgi) right \n textsubjectto theta_i - theta_texts = 0 i in mathcalN_textsb 5pt\n h_P_i(mathbf P_textg mathbf V bmTheta) = 0 forall i in mathcalN \n h_Q_i(mathbf Q_textg mathbf V bmTheta) = 0 forall i in mathcalN 5pt\n V_i^textmin leq V_i leq V_i^textmax forall i in mathcalN \n theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE 5pt\n F_ij^textmin leq h_ij(mathbf V bmTheta) leq F_ij^textmax forall (ij) in mathcalE \n F_ji^textmin leq h_ji(mathbf V bmTheta) leq F_ji^textmax forall (ij) in mathcalE 5pt\n P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS \n Q_textgi^textmin leq Q_textgi leq Q_textgi^textmax forall i in mathcalS\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In essence, the AC optimal power flow aims to minimize the objective function associated with the costs of generator's active and reactive power output while ensuring the fulfillment of all constraints. This optimization task plays a pivotal role in effectively managing electrical power systems. By striking a balance between cost reduction and constraint adherence, the AC optimal power flow contributes to efficient and reliable electricity supply in complex grid environments.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Build-Optimal-Power-Flow-Model","page":"AC Optimal Power Flow","title":"Build Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To build the AC optimal power flow model, we must first load the power system and establish the AC model:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"acModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Afterward, the AC optimal power flow model is created using the acOptimalPowerFlow function:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(\n system, Ipopt.Optimizer; active = \"Pg\", reactive = \"Qg\", magnitude = \"V\", angle = \"θ\"\n)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Optimization-Variables","page":"AC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The variables within this model encompass the active and reactive power outputs of the generators, denoted as mathbfP_textg = P_textgi and mathbfQ_textg = Q_textgi, where i in mathcalS, and the bus voltage magnitudes and angles represented by mathbfV = V_i and bmTheta = theta_i, where i in mathcalN. We can access these variables using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = analysis.method.variable.active\n𝐐ₒ = analysis.method.variable.reactive\n𝐕 = analysis.method.variable.magnitude\n𝚯 = analysis.method.variable.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Objective-Function","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The objective function represents the sum of the active and reactive power cost functions f_i(P_textgi) and f_i(Q_textgi), where i in mathcalS, for each generator, where these cost functions can be polynomial or linear piecewise. Typically, the AC optimal power flow focuses on minimizing the cost of active power outputs only, but for comprehensive analysis, we also consider the costs associated with reactive power outputs.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Polynomial-Cost-Function","page":"AC Optimal Power Flow","title":"Polynomial Cost Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the following analysis, we will focus on the cost function of generating active power, denoted as f_i(P_textgi). However, please note that the same analysis can be applied to the cost function f_i(Q_textgi) for reactive power.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow, the cost function f_i(P_textgi) can be represented as an n-th degree polynomial:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f_i(P_textgi) = sum_k=0^n a_k P_textgi^k","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Typically, cost functions are represented as linear, quadratic, or cubic, as shown in Figure 1:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n f_i(P_textgi) = a_1P_textgi + a_0 \n f_i(P_textgi) = a_2 P_textgi^2 + a_1P_textgi + a_0 \n f_i(P_textgi) = a_3 P_textgi^3 + a_2 P_textgi^2 + a_1P_textgi + a_0 \nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 1: The polynomial cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When using the cost! function in JuliaGrid and specifying the polynomial keyword, the polynomial is constructed with coefficients arranged in descending order of their degrees, from the highest degree to the lowest. For example, in the case study provided, we generated a cubic polynomial cost function for the active output power of Generator 1, which is represented as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n f_1(P_textg1) = 900 P_textg1^3 + 500 P_textg1^2 + 80 P_textg1 + 5\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these coefficients, users can utilize the variable:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f₁ = system.generator.cost.active.polynomial[1]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Linear-Piecewise-Cost-Function","page":"AC Optimal Power Flow","title":"Linear Piecewise Cost Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second option for defining cost functions in the AC optimal power flow is to use linear piecewise functions as approximations of the polynomial functions, as illustrated in Figure 2.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 2: The linear piecewise cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To define linear piecewise functions in JuliaGrid, users can utilize the cost! function with the piecewise keyword. The linear piecewise function is constructed using a matrix where each row defines a single point. The first column holds the generator's active or reactive power output, while the second column corresponds to the associated cost value. For example, in the provided case study, a linear piecewise function is created and can be accessed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f₂ = system.generator.cost.active.piecewise[2]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid handles convex linear piecewise functions using a constrained cost variable method. In this approach, the piecewise linear cost function is replaced by a helper variable and a set of linear inequality constraints for each segment of the function defined by two neighboring points along the line. However, for linear piecewise functions that have only one segment defined by two points, JuliaGrid transforms it into a standard linear function without introducing a helper variable.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Hence, for a piecewise cost function denoted as f_i(P_textgi) with k segments (where k 1), the j-th segment, defined by the points P_textgij f_i(P_textgij) and P_textgij+1 f_i(P_textgij+1), is characterized by the following inequality constraints:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"cfracf_i(P_textgij+1) - f_i(P_textgij)P_textgij+1 - P_textgij(P_textgi - P_textgij) + f_i(P_textgij) leq H_i i in mathcalS j = 1dotsk","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where H_i represents the helper variable. To finalize this method, we simply need to include the helper variable H_i in the objective function. This approach efficiently handles linear piecewise cost functions, providing the flexibility to capture nonlinear characteristics while still benefiting from the advantages of linear optimization techniques.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As an example, in the provided case study, the helper variable is defined as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"H₂ = analysis.method.variable.actwise[2]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Lastly, the set of constraints introduced by the linear piecewise cost function is displayed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.piecewise.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Objective-Function-2","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As previously explained, the objective function relies on the defined polynomial or linear piecewise cost functions and represents the sum of these costs. In the provided example, the objective function that must be minimized to obtain the optimal values for the active and reactive power outputs of the generators and the bus voltage magnitudes and angles can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Constraint-Functions","page":"AC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the following section, we will examine the various constraints defined within the AC optimal power flow model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Slack-Bus-Constraint","page":"AC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The first equality constraint is linked to the slack bus, where the bus voltage angle denoted as theta_i is fixed to a constant value theta_texts. It can be expressed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"theta_i - theta_texts = 0 i in mathcalN_textsb","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where the set mathcalN_textsb contains the index of the slack bus. To access the equality constraint from the model, we can utilize the variable:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.slack.angle)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Bus-Power-Balance-Constraints","page":"AC Optimal Power Flow","title":"Bus Power Balance Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second equality constraint in the optimization problem is associated with the active power balance equation:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\nh_P_i(mathbf P_textg mathbf V bmTheta) = 0 forall i in mathcalN\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As elaborated in the Bus Injections section, we can express the equation as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"h_P_i(mathbf P_textg mathbf V bmTheta) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - sum_k in mathcalS_i P_textgk + P_textdi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this equation, the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN, and P_textgk represents the active power output of the k-th generator within the set mathcalS_i. More Precisely, the variable P_textgk represents the optimization variable, along with the bus voltage angles theta_ij = theta_i - theta_j and the bus voltage magnitudes V_i and V_j.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term is determined by the active power demand P_textdi at bus i in mathcalN. The values representing this constant term, denoted as mathbfP_textd = P_textdi, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = system.bus.demand.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can access the references to the active power balance constraints using the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.balance.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the next constraint in the optimization problem is associated with the reactive power balance equation:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\nh_Q_i(mathbf Q_textg mathbf V bmTheta) = 0 forall i in mathcalN\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As elaborated in the Bus Injections section, we can express the equation as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"h_Q_i(mathbf Q_textg mathbf V bmTheta) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - sum_k in mathcalS_i Q_textgk + Q_textdi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As mentioned earlier for active power, Q_textgk represents the reactive power output of the k-th generator within the set mathcalS_i. The variable Q_textgk serves as an optimization variable, as well as the bus voltage angles theta_ij = theta_i - theta_j, and the bus voltage magnitudes V_i and V_j.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term is determined by the reactive power demand Q_textdi at bus i in mathcalN. The values representing this constant term, denoted as mathbfQ_textd = Q_textdi, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₒ = system.bus.demand.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can access the references to the reactive power balance constraints using the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.balance.reactive)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Bus-Voltage-Constraints","page":"AC Optimal Power Flow","title":"Bus Voltage Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraints associated with the voltage magnitude ensure that the bus voltage magnitudes are within specified limits:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"V_i^textmin leq V_i leq V_i^textmax forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where V_i^textmin represents the minimum voltage magnitude, and V_i^textmax represents the maximum voltage magnitude for bus i in mathcalN. The values representing these voltage magnitude limits, denoted as mathbfV_textlm = V_i^textmin V_i^textmax, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐕ₗₘ = [system.bus.voltage.minMagnitude system.bus.voltage.maxMagnitude]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To retrieve this inequality constraint from the model, we can use the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.magnitude)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraint related to the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch is defined as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where theta_ij^textmin represents the minimum, while theta_ij^textmax represents the maximum of the angle difference between adjacent buses. The values representing the voltage angle difference, denoted as bmTheta_textlm = theta_ij^textmin theta_ij^textmax, (ij) in mathcalE, are provided as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝚯ₗₘ = [system.branch.voltage.minDiffAngle system.branch.voltage.maxDiffAngle]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To retrieve this inequality constraint from the model, we can use the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.angle)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Branch-Flow-Constraints","page":"AC Optimal Power Flow","title":"Branch Flow Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraints related to the branch flow ratings can be associated with the limits on apparent power flow, active power flow, or current magnitude at the from-bus and to-bus ends of each branch. The type of constraint applied is determined by the type keyword within the addBranch! function.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Specifically, type = 1 is used for apparent power flow, type = 2 for active power flow, and type = 3 for current magnitude. These constraints can be expressed using the equations h_ij(mathbf V bmTheta) and h_ji(mathbf V bmTheta), representing the rating constraints at the from-bus and to-bus ends of each branch, respectively:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n F_ij^textmin leq h_ij(mathbf V bmTheta) leq F_ij^textmax forall (ij) in mathcalE \n F_ji^textmin leq h_ji(mathbf V bmTheta) leq F_ji^textmax forall (ij) in mathcalE\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The branch flow limits at the from-bus and to-bus ends, denoted as mathbfF_textf = F_ij^textmin F_ij^textmax and mathbfF_textt = F_ji^textmin F_ji^textmax, (ij) in mathcalE, can be retrieved as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐅ₒ = [system.branch.flow.minFromBus system.branch.flow.maxFromBus]\n𝐅ₜ = [system.branch.flow.minToBus system.branch.flow.maxToBus]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By default, JuliaGrid employs the rating constraints linked with the apparent power flow (type = 1). This constraint at the from-bus is specified as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" h_ij(mathbf V bmTheta) = sqrt A_ij V_i^4 + B_ij V_i^2 V_j^2 - 2 C_ij cos(theta_ij - phi_ij) - D_ij sin(theta_ij - phi_ij)V_i^3 V_j","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" begingathered\n A_ij = cfrac(g_ij + g_textsi)^2+(b_ij+b_textsi)^2tau_ij^4 B_ij = cfracg_ij^2+b_ij^2tau_ij^2 \n C_ij = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij^3 D_ij = cfracg_ijb_textsi - b_ijg_textsitau_ij^3\n endgathered","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Furthermore, this constraint at the to-bus is specified as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" h_ji(mathbf V bmTheta) = sqrt A_ji V_j^4 + B_ji V_i^2 V_j^2 - 2 C_ji cos(theta_ij - phi_ij) + D_ij sin(theta_ij - phi_ij)V_i V_j^3 ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" begingathered\n A_ji = (g_ij + g_textsi)^2+(b_ij+b_textsi)^2 B_ji = cfracg_ij^2+b_ij^2tau_ij^2 \n C_ji = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij D_ji = cfracg_ijb_textsi - b_ijg_textsitau_ij\n endgathered","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second option is to define the limit keywords for active power flow constraints (type = 2) at the from-bus and to-bus ends of each branch:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" beginaligned\n h_ij(mathbf V bmTheta) =\n cfrac g_ij + g_textsijtau_ij^2 V_i^2 -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)rightV_iV_j \n h_ji(mathbf V bmTheta) = (g_ij + g_textsij) V_j^2 -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij- phi_ij)right V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In our example, we have chosen to utilize this type of flow constraints. To access the flow constraints of branches at the from-bus end, you can use the following code snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.flow.from)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, to access the to-bus end flow constraints of branches you can use the following code snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.flow.to)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The last option involves defining the limit keywords for current magnitude constraints (type = 3) at the from-bus and to-bus ends of each branch. In this case, the constraints are implemented as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" beginaligned\n h_ij(mathbf V bmTheta) = sqrtA_ijV_i^2 + B_ijV_j^2 - 2C_ij cos(theta_ij - phi_ij) - D_ijsin(theta_ij - phi_ij)V_iV_j \n h_ji(mathbf V bmTheta) = sqrtA_jiV_j^2 + B_jiV_i^2 - 2C_ji cos(theta_ij - phi_ij) + D_jisin(theta_ij - phi_ij)V_iV_j\n endaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACPowerCapabilityConstraintsTutorials","page":"AC Optimal Power Flow","title":"Generator Power Capability Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The next set of constraints pertains to the minimum and maximum limits of active and reactive power outputs of the generators. These constraints ensure that the power outputs of the generators remain within specified bounds:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this representation, the lower and upper limits are determined by the vector mathbfP_textm = P_textgi^textmin P_textgi^textmax, i in mathcalS. We can access these bounds using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₘ = [system.generator.capability.minActive, system.generator.capability.maxActive]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these constraints, you can utilize the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.capability.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, constraints related to the minimum and maximum limits of reactive power outputs of the generators ensure that the reactive powers remain within specified boundaries:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Q_textgi^textmin leq Q_textgi leq Q_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Thus, the lower and upper limits are determined by the vector mathbfQ_textm = Q_textgi^textmin Q_textgi^textmax, i in mathcalS. We can access these bounds using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₘ = [system.generator.capability.minReactive system.generator.capability.maxReactive]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these constraints, you can use the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.capability.reactive)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These capability limits of the generators define the feasible region, represented as a gray area in Figure 3, which forms the solution space for the active and reactive output powers of the generators.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 3: The feasible region created by the active and reactive power capability constraints.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"However, this representation might not be the most accurate depiction of the generator's output power behavior. In reality, there exists a tradeoff between the active and reactive power outputs of the generators [8]. Specifically, when a generator operates at its maximum active power P_textgi^textmax, it may not be able to produce the maximum Q_textgi^textmax or minimum Q_textgi^textmin reactive power. To capture this tradeoff, we introduce the ability to include additional upper and lower constraints on the feasible region, leading to its reduction as shown in Figure 4.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 4: The feasible region created by the active and reactive power capability constraints with additional upper and lower constraints.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"If a user wishes to incorporate the tradeoff between active and reactive power outputs into the optimization model, they can define the points shown in Figure 4 within the addGenerator! function using the following keywords:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Keyword Coordinate\nlowActive P_textgi^textlow\nminLowReactive Q_textgitextlow^textmin\nmaxLowReactive Q_textgitextlow^textmax\nupActive P_textgi^textup\nminUpReactive Q_textgitextup^textmin\nmaxUpReactive Q_textgitextup^textmax","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When using these points, JuliaGrid constructs two additional capability constraints per generator as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n (Q_textgitextlow^textmax - Q_textgitextup^textmax)P_textgi + (P_textgi^textup - P_textgi^textlow)Q_textgi\n leq (Q_textgitextlow^textmax - Q_textgitextup^textmax)P_textgi^textlow + (P_textgi^textup - P_textgi^textlow)Q_textgitextlow^textmax \n (Q_textgitextup^textmin - Q_textgitextlow^textmin)P_textgi + (P_textgi^textlow - P_textgi^textup)Q_textgi\n leq (Q_textgitextup^textmin - Q_textgitextlow^textmin)P_textgi^textlow + (P_textgi^textlow - P_textgi^textup)Q_textgitextlow^textmin\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To ensure numerical stability, these constraints are normalized by introducing two scaling factors:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n s_1 = sqrt(Q_textgitextlow^textmax - Q_textgitextup^textmax)^2 + (P_textgi^textup - P_textgi^textlow)^2\n s_2 = sqrt(Q_textgitextup^textmin - Q_textgitextlow^textmin)^2 + (P_textgi^textlow - P_textgi^textup)^2\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When these constraints exist in the system, users can access them using the following variables:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.constraint.capability.upper\nanalysis.method.constraint.capability.lower\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These additional capability constraints allow us to accurately represent the tradeoff between active and reactive power outputs of the generators while maintaining numerical stability.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowSolutionTutorials","page":"AC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the optimal values of active and reactive power outputs for generators and the bus voltage magnitudes and angles, the user needs to invoke the following function:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After solving the AC optimal power flow problem, you can retrieve the vectors of output active and reactive power for generators, denoted as mathbfP_textg = P_textgi and mathbfQ_textg = Q_textgi, where i in mathcalS, using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = analysis.power.generator.active\n𝐐ₒ = analysis.power.generator.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the resulting bus voltage magnitudes and angles, represented by mathbfV = V_i and bmTheta = theta_i, where i in mathcalN, are stored in the vectors as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By accessing these vectors, you can analyze and utilize the optimal power flow solution for further studies or operational decision-making in the power system.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerAnalysisTutorials","page":"AC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-Injections","page":"AC Optimal Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#OptGeneratorPowerInjectionsManual","page":"AC Optimal Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The power! function in JuliaGrid also provides the computation of active and reactive power injections from the generators at each bus. To calculate the active power supplied by generators to the buses, one can simply sum the active power outputs of the generators obtained from the AC optimal power flow. This can be represented as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" P_textpi = sum_k in mathcalS_i P_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN. The active power injections from the generators at each bus are stored as a vector denoted by mathbfP_textp = P_textpi, and can be obtained using:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can obtain the reactive power supplied by generators to the buses:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" Q_textpi = sum_k in mathcalS_i Q_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The vector of these reactive power injections by the generators to the buses, denoted by mathbfQ_textp = Q_textpi, can be retrieved using the following command:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Bus-Shunt-Elements","page":"AC Optimal Power Flow","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-Flows","page":"AC Optimal Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Branch-Shunt-Elements","page":"AC Optimal Power Flow","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Branch-Series-Elements","page":"AC Optimal Power Flow","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Analysis","page":"AC Optimal Power Flow","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Injections","page":"AC Optimal Power Flow","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Flows","page":"AC Optimal Power Flow","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-at-Branch-Series-Elements","page":"AC Optimal Power Flow","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/measurementModel/#measurementModelAPI","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For further information on this topic, please see the Measurement Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate with measurement devices.","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To load measurement model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Measurement-Data","page":"Measurement Model","title":"Measurement Data","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement\nsaveMeasurement\nstatus!","category":"page"},{"location":"api/measurementModel/#Voltmeter","page":"Measurement Model","title":"Voltmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!\nupdateVoltmeter!\nstatusVoltmeter!\n@voltmeter","category":"page"},{"location":"api/measurementModel/#Ammeter","page":"Measurement Model","title":"Ammeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!\nupdateAmmeter!\nstatusAmmeter!\n@ammeter","category":"page"},{"location":"api/measurementModel/#Wattmeter","page":"Measurement Model","title":"Wattmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!\nupdateWattmeter!\nstatusWattmeter!\n@wattmeter","category":"page"},{"location":"api/measurementModel/#Varmeter","page":"Measurement Model","title":"Varmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!\nupdateVarmeter!\nstatusVarmeter!\n@varmeter","category":"page"},{"location":"api/measurementModel/#PMU","page":"Measurement Model","title":"PMU","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!\nupdatePmu!\nstatusPmu!\n@pmu","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Measurement-Data-2","page":"Measurement Model","title":"Measurement Data","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement\nsaveMeasurement\nstatus!","category":"page"},{"location":"api/measurementModel/#JuliaGrid.measurement","page":"Measurement Model","title":"JuliaGrid.measurement","text":"measurement(file::String)\n\nThe function builds the composite type Measurement and populates voltmeter, ammeter, wattmeter, varmeter, and pmu fields. In general, once the composite type Measurement has been created, it is possible to add new measurement devices, or modify the parameters of existing ones.\n\nArgument\n\nIt requires a string path to the HDF5 file with the .h5 extension.\n\nReturns\n\nThe Measurement composite type with the following fields:\n\nvoltmeter: Bus voltage magnitude measurements.\nammeter: Branch current magnitude measurements.\nwattmeter: Active power injection and active power flow measurements.\nvarmeter: Reactive power injection and reactive power flow measurements.\npmu: Bus voltage and branch current phasor measurements.\n\nUnits\n\nJuliaGrid stores all data in per-units and radians format.\n\nExample\n\ndevice = measurement(\"measurement14.h5\")\n\n\n\n\n\nmeasurement()\n\nAlternatively, the Measurement composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed.\n\nExample\n\ndevice = measurement()\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.saveMeasurement","page":"Measurement Model","title":"JuliaGrid.saveMeasurement","text":"saveMeasurement(device::Measurement; path::String, reference::String, note::String)\n\nThe function saves the measurement's data in the HDF5 file using the fields voltmeter, ammeter, wattmeter, varmeter, and pmu from the Measurement composite type.\n\nKeywords\n\nThe location and file name of the HDF5 file is specified by the mandatory keyword path in the format of \"path/name.h5\". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.\n\nView HDF5 File\n\nTo view the saved HDF5 file, you can use the HDFView software.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.m\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\n\nsaveMeasurement(device; path = \"D:/measurement14.h5\")\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.status!","page":"Measurement Model","title":"JuliaGrid.status!","text":"status!(system::PowerSystem, device::Measurement; inservice, outservice, redundancy)\n\nThe function generates a set of measurements, assigning measurement devices randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nOnly one of the following keywords can be used at a time to configure the measurement set:\n\ninservice: Sets the number of in-service devices.\noutservice: Sets the number of out-of-service devices.\nredundancy: Determines in-service devices based on redundancy.\n\nUpdates\n\nThe function updates all the status fields within the Measurement type.\n\nExamples\n\nCreating a measurement set with a specific number of in-service devices:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\n\nstatus!(system, device; inservice = 30)\n\nCreating a measurement set using redundancy:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\naddVarmeter!(system, device, analysis)\n\nstatus!(system, device; redundancy = 2.5)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Voltmeter-2","page":"Measurement Model","title":"Voltmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!(::PowerSystem, ::Measurement)\naddVoltmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateVoltmeter!\nstatusVoltmeter!\n@voltmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addVoltmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addVoltmeter!","text":"addVoltmeter!(system::PowerSystem, device::Measurement; label, bus, magnitude, variance,\n noise, status)\n\nThe function adds a new voltmeter that measures bus voltage magnitude to the Measurement type within a given PowerSystem type. The voltmeter can be added to an already defined bus.\n\nKeywords\n\nThe voltmeter is defined with the following keywords:\n\nlabel: Unique label for the voltmeter.\nbus: Label of the bus to which the voltmeter is connected.\nmagnitude (pu or V): Bus voltage magnitude value.\nvariance (pu or V): Variance of the bus voltage magnitude measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitude,\nnoise = false: uses the magnitude value only.\nstatus: Operating status of the voltmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the voltmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, and users can modify these default settings using the @voltmeter macro.\n\nUnits\n\nThe default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExamples\n\nAdding a voltmeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.1)\n\nAdding a voltmeter using a custom unit system:\n\n@voltage(kV, rad, kV)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 145.2)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addVoltmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addVoltmeter!","text":"addVoltmeter!(system::PowerSystem, device::Measurement, analysis::AC; variance, noise,\n status)\n\nThe function incorporates voltmeters into the Measurement composite type for every bus within the PowerSystem type. These measurements are derived from the exact bus voltage magnitudes defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvariance (pu or V): Variance of bus voltage magnitude measurements.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the voltage magnitudes,\nnoise = false: uses the exact voltage magnitude values.\nstatus: Operating status of the voltmeters:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the voltmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: variance = 1e-2, noise = false, and status = 1, and users can modify these default settings using the @voltmeter macro.\n\nUnits\n\nBy default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n@voltmeter(label = \"Voltmeter ?\")\naddVoltmeter!(system, device, analysis; variance = 1e-3, noise = true)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateVoltmeter!","page":"Measurement Model","title":"JuliaGrid.updateVoltmeter!","text":"updateVoltmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a voltmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific voltmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVoltmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing voltmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the voltmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addVoltmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.1)\nupdateVoltmeter!(system, device; label = \"Voltmeter 1\", magnitude = 0.9)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusVoltmeter!","page":"Measurement Model","title":"JuliaGrid.statusVoltmeter!","text":"statusVoltmeter!(system::PowerSystem, device::Measurement; inservice, outservice,\n redundancy)\n\nThe function generates a set of voltmeters, assigning voltmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nOnly one of the following keywords can be used at a time to configure the measurement set:\n\ninservice: Sets the number of in-service voltmeters.\noutservice: Sets the number of out-of-service voltmeters.\nredundancy: Determines in-service voltmeters based on redundancy.\n\nUpdates\n\nThe function updates the status field within the Voltmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\naddVoltmeter!(system, device, analysis)\nstatusVoltmeter!(system, device; inservice = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@voltmeter","page":"Measurement Model","title":"JuliaGrid.@voltmeter","text":"@voltmeter(label, variance, noise, status)\n\nThe macro generates a template for a voltmeter, which can be utilized to define a voltmeter using the addVoltmeter! function.\n\nKeywords\n\nTo establish the voltmeter template, users can specify default values for the variance, noise, and status keywords, along with pattern for labels using the label keyword.\n\nUnits\n\nBy default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExamples\n\nAdding a voltmeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\n@voltmeter(label = \"Voltmeter ?\", variance = 1e-5)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.1)\n\nAdding a voltmeter using a custom unit system:\n\n@voltage(kV, rad, kV)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\n\n@voltmeter(label = \"Voltmeter ?\", variance = 0.00132)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 145.2)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Ammeter-2","page":"Measurement Model","title":"Ammeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(::PowerSystem, ::Measurement)\naddAmmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateAmmeter!\nstatusAmmeter!\n@ammeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addAmmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addAmmeter!","text":"addAmmeter!(system::PowerSystem, device::Measurement; label, from, to, magnitude,\n variance, noise, status)\n\nThe function adds a new ammeter that measures branch current magnitude to the Measurement type within a given PowerSystem type. The ammeter can be added to an already defined branch.\n\nKeywords\n\nThe ammeter is defined with the following keywords:\n\nlabel: Unique label for the ammeter.\nfrom: Label of the branch if the ammeter is located at the from-bus end.\nto: Label of the branch if the ammeter is located at the to-bus end.\nmagnitude (pu or A): Branch current magnitude value.\nvariance (pu or A): Variance of the branch current magnitude measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitude,\nnoise = false: uses the magnitude value only.\nstatus: Operating status of the ammeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the ammeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, which apply to ammeters located at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for ammeters positioned on either the from-bus or to-bus ends of branches using the @ammeter macro.\n\nUnits\n\nThe default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExamples\n\nAdding ammeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 1.0)\n\nAdding ammeters using a custom unit system:\n\n@current(A, rad)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 481.125)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 437.386)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addAmmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addAmmeter!","text":"addAmmeter!(system::PowerSystem, device::Measurement, analysis::AC; varianceFrom,\n statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates ammeters into the Measurement type for every branch within the PowerSystem type. These measurements are derived from the exact branch current magnitudes defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceFrom (pu or A): Measurement variance for ammeters at the from-bus ends.\nstatusFrom: Operating status of the ammeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or A): Measurement variance for ammeters at the to-bus ends.\nstatusTo: Operating status of the ammeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the current magnitudes,\nnoise = false: uses the exact current magnitude values.\n\nUpdates\n\nThe function updates the ammeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @ammeter macro.\n\nUnits\n\nThe default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\n@ammeter(label = \"Ammeter ?\")\naddAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateAmmeter!","page":"Measurement Model","title":"JuliaGrid.updateAmmeter!","text":"updateAmmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for an ammeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific ammeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addAmmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing ammeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the ammeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addAmmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\nupdateAmmeter!(system, device; label = \"Ammeter 1\", magnitude = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusAmmeter!","page":"Measurement Model","title":"JuliaGrid.statusAmmeter!","text":"statusAmmeter!(system::PowerSystem, ammeter::Ammeter; inservice, inserviceFrom,\n inserviceTo, outservice, outserviceFrom, outserviceTo, redundancy, redundancyFrom,\n redundancyTo)\n\nThe function generates a set of ammeters, assigning ammeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or two fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service ammeters or allows fine-tuning:\ninserviceFrom: sets only ammeters loacted at the from-bus end,\ninserviceTo: sets only ammeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service ammeters or allows fine-tuning:\noutserviceFrom: sets only ammeters loacted at the from-bus end,\noutserviceTo: sets only ammeters loacted at the to-bus end.\nredundancy: Determines in-service ammeters based on redundancy or allows fine-tuning:\nredundancyFrom: determines only ammeters loacted at the from-bus end,\nredundancyTo: determines only ammeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Ammeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\naddAmmeter!(system, device, analysis)\nstatusAmmeter!(system, device; inserviceFrom = 5, inserviceTo = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@ammeter","page":"Measurement Model","title":"JuliaGrid.@ammeter","text":"@ammeter(label, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe macro generates a template for an ammeter, which can be utilized to define an ammeter using the addAmmeter! function.\n\nKeywords\n\nTo establish the ammeter template, users can set default variance and status values for ammeters at both the from-bus and to-bus ends of branches, using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExamples\n\nAdding an ammeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@ammeter(label = \"Ammeter ?\", varianceTo = 1e-3, statusTo = 0)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 1.1)\n\nAdding an ammeter using a custom unit system:\n\n@current(A, rad)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@ammeter(label = \"Ammeter ?\", varianceTo = 0.004374, statusTo = 0)\naddAmmeter!(system, device; label = \"Ammeter 1\", to = \"Branch 1\", magnitude = 481.125)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Wattmeter-2","page":"Measurement Model","title":"Wattmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(::PowerSystem, ::Measurement)\naddWattmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateWattmeter!\nstatusWattmeter!\n@wattmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addWattmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addWattmeter!","text":"addWattmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, active,\n variance, noise, status)\n\nThe function adds a new wattmeter that measures active power injection or active power flow to the Measurement type within a given PowerSystem type. The wattmeter can be added to an already defined bus or branch.\n\nKeywords\n\nThe wattmeter is defined with the following keywords:\n\nlabel: Unique label for the wattmeter.\nbus: Label of the bus if the wattmeter is located at the bus.\nfrom: Label of the branch if the wattmeter is located at the from-bus end.\nto: Label of the branch if the wattmeter is located at the to-bus end.\nactive (pu or W): Active power value.\nvariance (pu or W): Variance of the active power measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the active,\nnoise = false: uses the active value only.\nstatus: Operating status of the wattmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the wattmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to wattmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for wattmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @wattmeter macro.\n\nUnits\n\nThe default units for the active and variance keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExamples\n\nAdding wattmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 2\", active = 0.4)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 0.1)\n\nAdding wattmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 2\", active = 40.0)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 10.0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addWattmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addWattmeter!","text":"addWattmeter!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates wattmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact active power injections at buses and active power flows in branches defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceBus (pu or W): Measurement variance for wattmeters at the buses.\nstatusBus: Operating status of the wattmeters at the buses:\nstatusBus = 1: in-service,\nstatusBus = 0: out-of-service.\nvarianceFrom (pu or W): Measurement variance for wattmeters at the from-bus ends.\nstatusFrom: Operating status of the wattmeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or W): Measurement variance for wattmeters at the to-bus ends.\nstatusTo: Operating status of the wattmeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the active powers,\nnoise = false: uses the exact active power values.\n\nUpdates\n\nThe function updates the wattmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @wattmeter macro.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateWattmeter!","page":"Measurement Model","title":"JuliaGrid.updateWattmeter!","text":"updateWattmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a wattmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific wattmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addWattmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing wattmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the wattmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addWattmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 1.1)\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", active = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusWattmeter!","page":"Measurement Model","title":"JuliaGrid.statusWattmeter!","text":"statusWattmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of wattmeters, assigning wattmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service wattmeters or allows fine-tuning:\ninserviceBus: sets only wattmeters loacted at the bus,\ninserviceFrom: sets only wattmeters loacted at the from-bus end,\ninserviceTo: sets only wattmeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service wattmeters or allows fine-tuning:\noutserviceBus: sets only wattmeters loacted at the bus,\noutserviceFrom: sets only wattmeters loacted at the from-bus end,\noutserviceTo: sets only wattmeters loacted at the to-bus end.\nredundancy: Determines in-service wattmeters based on redundancy or allows fine-tuning:\nredundancyBus: determines only wattmeters loacted at the bus,\nredundancyFrom: determines only wattmeters loacted at the from-bus end,\nredundancyTo: determines only wattmeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Wattmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddWattmeter!(system, device, analysis)\nstatusWattmeter!(system, device; outserviceBus = 14, inserviceFrom = 10, outserviceTo = 2)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@wattmeter","page":"Measurement Model","title":"JuliaGrid.@wattmeter","text":"@wattmeter(label, varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo,\n noise)\n\nThe macro generates a template for a wattmeter, which can be utilized to define a wattmeter using the addWattmeter! function.\n\nKeywords\n\nTo establish the wattmeter template, users can set default variance and status values for wattmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExamples\n\nAdding wattmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@wattmeter(label = \"Wattmeter ?\", varianceBus = 1e-3, varianceFrom = 1e-4)\naddWattmeter!(system, device; bus = \"Bus 2\", active = 0.4)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.1)\n\nAdding wattmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@wattmeter(label = \"Wattmeter ?\", varianceBus = 1e-1, varianceFrom = 1e-2)\naddWattmeter!(system, device; bus = \"Bus 2\", active = 40.0)\naddWattmeter!(system, device; from = \"Branch 1\", active = 10.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Varmeter-2","page":"Measurement Model","title":"Varmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(::PowerSystem, ::Measurement)\naddVarmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateVarmeter!\nstatusVarmeter!\n@varmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addVarmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addVarmeter!","text":"addVarmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, reactive,\n variance, noise, status)\n\nThe function adds a new varmeter that measures reactive power injection or reactive power flow to the Measurement type within a given PowerSystem type. The varmeter can be added to an already defined bus or branch.\n\nKeywords\n\nThe varmeter is defined with the following keywords:\n\nlabel: Unique label for the varmeter.\nbus: Label of the bus if the varmeter is located at the bus.\nfrom: Label of the branch if the varmeter is located at the from-bus end.\nto: Label of the branch if the varmeter is located at the to-bus end.\nreactive (pu or VAr): Reactive power value.\nvariance (pu or VAr): Variance of the reactive power measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the reactive,\nnoise = false: uses the reactive value only.\nstatus: Operating status of the varmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the varmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to varmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for varmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @varmeter macro.\n\nUnits\n\nThe default units for the reactive and variance keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExamples\n\nAdding varmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 2\", reactive = 0.4)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 0.1)\n\nAdding varmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 2\", reactive = 40.0)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 10.0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addVarmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addVarmeter!","text":"addVarmeter!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates varmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact reactive power injections at buses and reactive power flows in branches defined in the AC type.\n\nKeywords\n\nvarianceBus (pu or VAr): Measurement variance for varmeters at the buses.\nstatusBus: Operating status of the varmeters at the buses:\nstatusBus = 1: in-service,\nstatusBus = 0: out-of-service.\nvarianceFrom (pu or VAr): Measurement variance for varmeters at the from-bus ends.\nstatusFrom: Operating status of the varmeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or VAr): Measurement variance for varmeters at the to-bus ends.\nstatusTo: Operating status of the varmeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the reactive powers,\nnoise = false: uses the exact reactive power values.\n\nUpdates\n\nThe function updates the varmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @varmeter macro.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n@varmeter(label = \"Varmeter ?\")\naddVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateVarmeter!","page":"Measurement Model","title":"JuliaGrid.updateVarmeter!","text":"updateVarmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a varmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific varmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVarmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing varmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the varmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addVarmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = 1.1)\nupdateVarmeter!(system, device; label = \"Varmeter 1\", reactive = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusVarmeter!","page":"Measurement Model","title":"JuliaGrid.statusVarmeter!","text":"statusVarmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of varmeters, assigning varmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service varmeters or allows fine-tuning:\ninserviceBus: sets only varmeters loacted at the bus,\ninserviceFrom: sets only varmeters loacted at the from-bus end,\ninserviceTo: sets only varmeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service varmeters or allows fine-tuning:\noutserviceBus: sets only varmeters loacted at the bus,\noutserviceFrom: sets only varmeters loacted at the from-bus end,\noutserviceTo: sets only varmeters loacted at the to-bus end.\nredundancy: Determines in-service varmeters based on redundancy or allows fine-tuning:\nredundancyBus: determines only varmeters loacted at the bus,\nredundancyFrom: determines only varmeters loacted at the from-bus end,\nredundancyTo: determines only varmeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Varmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVarmeter!(system, device, analysis)\nstatusVarmeter!(system, device; inserviceFrom = 20)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@varmeter","page":"Measurement Model","title":"JuliaGrid.@varmeter","text":"@varmeter(label, varinaceBus, varianceFrom, varianceTo, statusBus, statusFrom, statusTo,\n noise)\n\nThe macro generates a template for a varmeter, which can be utilized to define a varmeter using the addVarmeter! function.\n\nKeywords\n\nTo establish the varmeter template, users can set default variance and status values for varmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to usevolt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExamples\n\nAdding varmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@varmeter(label = \"Varmeter ?\", varianceBus = 1e-3, varianceFrom = 1e-4)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = 0.4)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.1)\n\nAdding varmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@varmeter(label = \"Varmeter ?\", varianceBus = 1e-1, varianceFrom = 1e-2)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = 40.0)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 10.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#PMU-2","page":"Measurement Model","title":"PMU","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(::PowerSystem, ::Measurement)\naddPmu!(::PowerSystem, ::Measurement, ::AC)\nupdatePmu!\nstatusPmu!\n@pmu","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addPmu!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addPmu!","text":"addPmu!(system::PowerSystem, device::Measurement; label, bus, from, to, magnitude,\n varianceMagnitude, statusMagnitude, angle, varianceAngle, statusAngle,\n noise, correlated, polar)\n\nThe function adds a new PMU to the Measurement type within a given PowerSystem type. The PMU can be added to an already defined bus or branch. When defining the PMU, it is essential to provide the bus voltage magnitude and angle if the PMU is located at a bus or the branch current magnitude and angle if the PMU is located at a branch.\n\nKeywords\n\nThe PMU is defined with the following keywords:\n\nlabel: Unique label for the PMU.\nbus: Label of the bus if the PMU is located at the bus.\nfrom: Label of the branch if the PMU is located at the from-bus end.\nto: Label of the branch if the PMU is located at the to-bus end.\nmagnitude (pu or V, A): Bus voltage or branch current magnitude value.\nvarianceMagnitude (pu or V, A): Magnitude measurement variance.\nstatusMagnitude: Operating status of the magnitude measurement:\nstatusMagnitude = 1: in-service,\nstatusMagnitude = 0: out-of-service.\nangle (rad or deg): Bus voltage or branch current angle value.\nvarianceAngle (rad or deg): Angle measurement variance.\nstatusAngle: Operating status of the angle measurement:\nstatusAngle = 1: in-service,\nstatusAngle = 0: out-of-service.\nnoise: Specifies how to generate the measurement means:\nnoise = true: adds white Gaussian noises with variances to the magnitude and angle,\nnoise = false: uses the magnitude and angle values only.\ncorrelated: Specifies error correlation for PMUs for algorithms utilizing rectangular coordinates:\ncorrelated = true: considers correlated errors,\ncorrelated = false: disregards correlations between errors.\npolar: Chooses the coordinate system for including phasor measurements in AC state estimation:\npolar = true: adopts the polar coordinate system,\npolar = false: adopts the rectangular coordinate system.\n\nUpdates\n\nThe function updates the pmu field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: varianceMagnitude = 1e-5, statusMagnitude = 1, varianceAngle = 1e-5, statusAngle = 1, noise = false, correlated = false, and polar = false, which apply to PMUs located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for PMUs positioned at the buses, from-bus ends, or to-bus ends of branches using the @pmu macro.\n\nUnits\n\nThe default units for the magnitude, varianceMagnitude, and angle, varianceAngle keywords are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) when the PMU is located at a bus using the @voltage macro, or amperes (A) and degrees (deg) when the PMU is located at a branch through the use of the @current macro.\n\nExamples\n\nAdding PMUs using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 131.8e3)\naddBus!(system; label = \"Bus 2\", base = 131.8e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 1.1, angle = 0.1)\n\nAdding PMUs using a custom unit system:\n\n@voltage(kV, deg, kV)\n@current(A, deg)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 131.8)\naddBus!(system; label = \"Bus 2\", base = 131.8)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 145, angle = -5.7)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 481, angle = 5.7)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addPmu!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addPmu!","text":"addPmu!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,\n varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,\n varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo,\n correlated, polar, noise)\n\nThe function incorporates PMUs into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact bus voltage magnitudes and angles, as well as branch current magnitudes and angles defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceMagnitudeBus (pu or V): Variance of magnitude measurements at buses.\nstatusMagnitudeBus: Operating status of magnitude measurements at buses:\nstatusMagnitudeBus = 1: in-service,\nstatusMagnitudeBus = 0: out-of-service.\nvarianceAngleBus (rad or deg): Variance of angle measurements at buses.\nstatusAngleBus: Operating status of angle measurements at buses:\nstatusAngleBus = 1: in-service,\nstatusAngleBus = 0: out-of-service.\nvarianceMagnitudeFrom (pu or A): Variance of magnitude measurements at the from-bus ends.\nstatusMagnitudeFrom: Operating status of magnitude measurements at the from-bus ends:\nstatusMagnitudeFrom = 1: in-service,\nstatusMagnitudeFrom = 0: out-of-service.\nvarianceAngleFrom (rad or deg): Variance of angle measurements at the from-bus ends.\nstatusAngleFrom: Operating status of angle measurements at the from-bus ends:\nstatusAngleFrom = 1: in-service,\nstatusAngleFrom = 0: out-of-service.\nvarianceMagnitudeTo (pu or A): Variance of magnitude measurements at the to-bus ends.\nstatusMagnitudeTo: Operating status of magnitude measurements at the to-bus ends:\nstatusMagnitudeTo = 1: in-service,\nstatusMagnitudeTo = 0: out-of-service.\nvarianceAngleTo (rad or deg): Variance of angle measurements at the to-bus ends.\nstatusAngleTo: Operating status of angle measurements at the to-bus ends:\nstatusAngleTo = 1: in-service,\nstatusAngleTo = 0: out-of-service.\ncorrelated: Specifies error correlation for PMUs for algorithms utilizing rectangular coordinates:\ncorrelated = true: considers correlated errors,\ncorrelated = false: disregards correlations between errors.\npolar: Chooses the coordinate system for including phasor measurements in AC state estimation:\npolar = true: adopts the polar coordinate system,\npolar = false: adopts the rectangular coordinate system.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitudes and angles,\nnoise = false: uses the exact magnitude and angles values.\n\nUpdates\n\nThe function updates the pmu field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for variance keywords are established at 1e-5, with all statuses set to 1, polar = false, correlated = false, and noise = false. Users can change these default settings using the @pmu macro.\n\nUnits\n\nThe default units for the variance keywords are in per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) when the PMU is located at a bus using the @voltage macro, or amperes (A) and degrees (deg) when the PMU is located at a branch through the use of the @current macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updatePmu!","page":"Measurement Model","title":"JuliaGrid.updatePmu!","text":"updatePmu!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a PMU.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific PMU, provide the necessary kwargs input arguments in accordance with the keywords specified in the addPmu! function, along with their respective values. Ensure that the label keyword matches the label of the existing PMU you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the pmu field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addPmu! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\nupdatePmu!(system, device; label = \"PMU 1\", magnitude = 1.05)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusPmu!","page":"Measurement Model","title":"JuliaGrid.statusPmu!","text":"statusPmu!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of PMUs, assigning PMUs randomly to either in-service or out-of-service states based on specified keywords. It is important to note that when we refer to PMU, we encompass both magnitude and angle measurements.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service PMUs or allows fine-tuning:\ninserviceBus: sets only PMUs loacted at the bus,\ninserviceFrom: sets only PMUs loacted at the from-bus end,\ninserviceTo: sets only PMUs loacted at the to-bus end.\noutservice: Sets the number of out-of-service PMUs or allows fine-tuning:\noutserviceBus: sets only PMUs loacted at the bus,\noutserviceFrom: sets only PMUs loacted at the from-bus end,\noutserviceTo: sets only PMUs loacted at the to-bus end.\nredundancy: Determines in-service PMUs based on redundancy or allows fine-tuning:\nredundancyBus: determines only PMUs loacted at the bus,\nredundancyFrom: determines only PMUs loacted at the from-bus end,\nredundancyTo: determines only PMUs loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status fields within the PMU type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\naddPmu!(system, device, analysis)\nstatusPmu!(system, device; inserviceBus = 14)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@pmu","page":"Measurement Model","title":"JuliaGrid.@pmu","text":"@pmu(label, varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,\n varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,\n varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo, noise,\n correlated, polar)\n\nThe macro generates a template for a PMU, which can be utilized to define a PMU using the addPmu! function.\n\nKeywords\n\nTo establish the PMU template, users have the option to set default values for magnitude and angle variances, as well as statuses for each component of the phasor. This can be done for PMUs located at the buses using the varianceMagnitudeBus, varianceAngleBus, statusMagnitudeBus, and statusAngleBus keywords.\n\nThe same configuration can be applied at both the from-bus ends of the branches using the varianceMagnitudeFrom, varianceAngleFrom, statusMagnitudeFrom, and statusAngleFrom keywords.\n\nFor PMUs located at the to-bus ends of the branches, users can use the varianceMagnitudeTo, varianceAngleTo, statusMagnitudeTo, and statusAngleTo keywords.\n\nAdditionally, users can configure the pattern for labels using the label keyword, specify the type of noise, and indicate the correlated and polar system utilized for managing phasors during state estimation.\n\nUnits\n\nBy default, the units for variances are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) as the units for PMUs located at the buses by using the @voltage macro, or they can switch to amperes (A) and degrees (deg) as the units for PMUs located at the branches by using the @current macro.\n\nExamples\n\nAdding PMUs using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@pmu(label = \"PMU ?\", varianceAngleBus = 1e-6, varianceMagnitudeFrom = 1e-4)\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 1.1, angle = -0.2)\n\nAdding PMUs using a custom unit system:\n\n@voltage(kV, deg, kV)\n@current(A, deg)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\naddBus!(system; label = \"Bus 2\", base = 132.0)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@pmu(label = \"PMU ?\", varianceAngleBus = 5.73e-5, varianceMagnitudeFrom = 0.0481)\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 145.2, angle = -5.73)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 481.125, angle = -11.46)\n\n\n\n\n\n","category":"macro"},{"location":"manual/dcStateEstimation/#DCStateEstimationManual","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To perform the DC state estimation, we first need to have the PowerSystem type that has been created with the DC model, alongside the Measurement type that retains measurement data. Subsequently, we can formulate either the weighted least-squares (WLS) or the least absolute value (LAV) DC state estimation model encapsulated within the type DCStateEstimation using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"dcStateEstimation,\ndcLavStateEstimation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For resolving the DC state estimation problem and obtaining bus voltage angles, utilize the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After executing the function solve!, where the user employs the WLS method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Moreover, before creating the DCStateEstimation type, users can initiate observability analysis to identify observable islands and restore observability by employing:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"islandTopologicalFlow,\nislandTopological,\nrestorationGram!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For more detailed information, users can refer to the Observability Analysis section within AC state estimation documentation. It is worth noting that when the system becomes observable within the AC model, it will also be observable within the DC state estimation model.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution for DC state estimation, JuliaGrid offers a post-processing analysis function to compute active powers associated with buses and branches:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses or branches.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCSEBusTypeModificationManual","page":"DC State Estimation","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Just like in the Bus Type Modification section, when establishing the DCStateEstimation type, the initially assigned slack bus is evaluated and may be altered. If the designated slack bus (type = 3) lacks a connected in-service generator, it will be changed to a demand bus (type = 1). Conversely, the first generator bus (type = 2) with an active in-service generator linked to it will be reassigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCWLSStateEstimationSolutionManual","page":"DC State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To solve the DC state estimation and derive WLS estimates using JuliaGrid, the process initiates by defining PowerSystem and Measurement types. Here is an illustrative example:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.2)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.4)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.2)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 3\", active = -0.4, variance = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.18, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 2\", active = -0.42, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The dcStateEstimation function serves to establish the DC state estimation problem:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the DC state estimation problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = dcStateEstimation(system, device, LDLt)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain the bus voltage angles, the solve! function can be invoked as shown:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Upon obtaining the solution, access the bus voltage angles using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe recommend that readers refer to the tutorial on DC State Estimation for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Alternative-Formulation","page":"DC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Specifically, by specifying the Orthogonal argument in the dcStateEstimation function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device, Orthogonal)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Print-Results-in-the-REPL","page":"DC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Save-Results-to-a-File","page":"DC State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nWe also provide functions to print state estimation results, such as estimated values and residuals. For more details, users can consult the Power Analysis section of this manual.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCBadDataDetectionManual","page":"DC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After acquiring the WLS solution using the solve! function, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new wattmeter. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; from = \"Branch 2\", active = 4.1, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the DC state estimation model:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective measurements as out-of-service within the Measurement type.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Moreover, JuliaGrid will adjust the coefficient matrix and mean vector within the DCStateEstimation type based on measurements now designated as out-of-service. To optimize the algorithm's efficiency, JuliaGrid resets non-zero elements to zero in the coefficient matrix and mean vector, effectively removing the impact of the corresponding measurement on the solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis.method.mean\nanalysis.method.coefficient","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, after removing bad data, a new estimate can be computed without considering this specific measurement:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCLAVtateEstimationSolutionManual","page":"DC State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Setup-Starting-Primal-Values","page":"DC State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the DCStateEstimation type. By default, these values are initially established using the initial bus voltage angles from PowerSystem type:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Solution","page":"DC State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Upon obtaining the solution, access the bus voltage angles using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCMeasurementsAlterationManual","page":"DC State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the DCStateEstimation type using the dcStateEstimation or dcLavStateEstimation function. Ultimately, resolving the DC state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.1)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.11, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.09, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for the model\nsolve!(system, analysis)\n\naddWattmeter!(system, device; to = \"Branch 1\", active = -0.12, variance = 1e-4)\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", status = 0)\nupdateWattmeter!(system, device; label = \"Wattmeter 2\", active = 0.1, noise = false)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for new model\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCStateEstimationUpdateManual","page":"DC State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"An advanced methodology involves users establishing the DCStateEstimation type using dcStateEstimation or dcLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the DCStateEstimation type.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where DCStateEstimation also does not need to be recreated. Such efficiency can be particularly advantageous in cases where JuliaGrid can reuse gain matrix factorization.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of DCStateEstimation is not practical in terms of reusing this type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can modify the prior example to achieve the same model without establishing DCStateEstimation twice:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.1)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.11, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.09, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 1\", active = -0.12, variance = 1e-4, status = 0)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for the model\nsolve!(system, analysis)\n\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", status = 0)\nupdateWattmeter!(system, device; label = \"Wattmeter 2\", active = 0.1, noise = false)\nupdateWattmeter!(system, device; label = \"Wattmeter 3\", status = 1)\n\n# <- No need for re-build; we have already updated the existing DCStateEstimation instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the DCStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Reusing-Weighted-Least-Squares-Matrix-Factorization","page":"DC State Estimation","title":"Reusing Weighted Least-Squares Matrix Factorization","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Drawing from the preceding example, our focus now shifts to finding a solution involving modifications that entail adjusting the measurement value of the Wattmeter 2. It is important to note that these adjustments do not impact the variance or status of the measurement device, which can affect the gain matrix. To resolve this updated system, users can simply execute the solve! function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 2\", active = 0.091)\n\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nIn this scenario, JuliaGrid will recognize instances where the user has not modified parameters that impact the gain matrix. Consequently, JuliaGrid will leverage the previously performed gain matrix factorization, resulting in a significantly faster solution compared to recomputing the factorization.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCSEPowerAnalysisManual","page":"DC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution from the DC state estimation, calculating powers related to buses and branches is facilitated by using the power! function. For instance, let us consider the model for which we obtained the DC state estimation solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, conductance = 1e-3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.2)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.4)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.2)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 3\", active = -0.4, variance = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.18, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 2\", active = -0.42, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can compute active powers using the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example, active power injections corresponding to buses are:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.power.injection.active)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nTo better understand the powers associated with buses, and branches that are calculated by the power! function, we suggest referring to the tutorials on.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Print-Results-in-the-REPL-2","page":"DC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can utilize any of the print functions outlined in the Print API related to the DC analysis. For example, to print state estimation data related to wattmeters, we can use:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"@power(MW, pu, pu)\nprintWattmeterData(system, device, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Save-Results-to-a-CSV-File","page":"DC State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintWattmeterData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Injection","page":"DC State Estimation","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Injection-from-Generators","page":"DC State Estimation","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Flow","page":"DC State Estimation","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = fromPower(system, analysis; label = \"Branch 1\")\nactive = toPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"tutorials/acPowerFlow/#ACPowerFlowTutorials","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid uses standard network components and the Unified Branch Model for power flow analysis, allowing load profiles, generator capacities, voltage specifications, contingency analysis, and planning to be defined efficiently.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7, reactive = 12.7)\naddBus!(system; label = 3, type = 1, active = 11.2, reactive = -3.0)\naddBus!(system; label = 4, type = 2, conductance = 2.1, susceptance = 1.2)\n\naddBranch!(system; from = 1, to = 2, resistance = 0.02, reactance = 0.06)\naddBranch!(system; from = 1, to = 3, resistance = 0.05, reactance = 0.21)\naddBranch!(system; from = 2, to = 3, resistance = 0.13, reactance = 0.26)\naddBranch!(system; from = 3, to = 4, reactance = 0.17, susceptance = 0.2, conductance = 1e-4)\n\naddGenerator!(system; bus = 1)\naddGenerator!(system; bus = 3, active = 40.0, reactive = 42.4)\nnothing #hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = hcat([𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]])","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element associated with bus i in mathcalN, and a_ij represents the element associated with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#FlowNodalNetworkEquationsTutorials","page":"AC Power Flow","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As previously demonstrated in the section on the Nodal Network Equations, we observe the system of equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfbar I = mathbfY mathbfbar V","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The complex current injection at the bus i in mathcalN is defined as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barI_i = cfracS_i^*barV_i^*","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, for any given bus i in mathcalN, we can express it as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" cfracS_i^*barV_i^* = sum_j = 1^n Y_ij bar V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The complex power injection denoted by S_i consists of both the active power P_i and reactive power Q_i. This relationship can be represented as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" cfracP_i - textjQ_ibarV_i = sum_j = 1^n Y_ij bar V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Recognizing that Y_ij = G_ij + textjB_ij, barV_i = V_i texte^textjtheta_i, barV_j = V_j texte^textjtheta_j, and by defining theta_ij = theta_i - theta_j, we can break down the above equation into its real and imaginary parts, resulting in two equations that describe bus i in mathcalN as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n P_i =V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j\n Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As demonstrated by the above equations, the bus i in mathcalN contains four unknown variables: the active power injection P_i, reactive power injection Q_i, bus voltage magnitude V_i, and bus voltage angle theta_i.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To solve these equations, it is necessary to specify two known variables. Although any two variables can be selected mathematically, the choice is determined by the devices that are connected to a particular bus. The standard options are listed in the table below, and these options are used to define the bus types [9].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Type Label Known Unknown\nDemand 1 P_i, Q_i V_i, theta_i\nGenerator 2 P_i, V_i Q_i, theta_i\nSlack 3 V_i, theta_i P_i, Q_i","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Consequently, JuliaGrid operates with sets mathcalN_textpq and mathcalN_textpv that contain demand and generator buses, respectively, and exactly one slack bus in the set mathcalN_textsb. The bus types are stored in the variable:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system.bus.layout.type","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"It should be noted that JuliaGrid cannot handle systems with multiple slack buses. Additionally, when using functions such as newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, and gaussSeidel, the bus type can be modified as discussed in the section on Bus Type Modification.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Furthermore, active power injections P_i and reactive power injections Q_i can be expressed as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n \tP_i = P_textpi - P_textdi \n Q_i = Q_textpi - Q_textdi\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textdi and Q_textdi denote the active and reactive power demanded at the bus i in mathcalN, while P_textpi and Q_textpi correspond to the active and reactive power produced by the generators at the bus i in mathcalN.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To provide a more comprehensive understanding, it is important to note that each bus i in mathcalN has the capacity to host multiple generators. This scenario can be conceptualized by introducing the set mathcalS_i, which encompasses all generators connected to bus i in mathcalN. With this perspective, we can calculate the values of P_textpi and Q_textpi as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n \tP_textpi = sum_k in mathcalS_i P_textgk\n Q_textpi = sum_k in mathcalS_i Q_textgk\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textgk and Q_textgk represent the active and reactive power outputs of the k-th generator within the set mathcalS_i.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As a way to summarize, the power injection vectors, represented as mathbfP = P_i and mathbfQ = Q_i can be computed based on the following variables and expressions:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏 = system.bus.supply.active - system.bus.demand.active\n𝐐 = system.bus.supply.reactive - system.bus.demand.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Positive active or reactive power values, P_i 0 or Q_i 0, signify that power is being supplied into the power system from the specific bus. This indicates that the generators connected to this bus are producing more power than what the connected load is consuming. Conversely, negative values, P_i 0 or Q_i 0, indicate that the bus is drawing in active or reactive power from the power system. This suggests that the load's demand is exceeding the output from the generators.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#NewtonRaphsonMethodTutorials","page":"AC Power Flow","title":"Newton-Raphson Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Newton-Raphson method is commonly used in AC power flow calculations due to its quadratic rate of convergence. It provides an accurate approximation of the roots of the system of nonlinear equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbff(mathbfx) = mathbf0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This, in turn, allows for the determination of unknown voltage magnitudes and angles of buses, represented by the state vector mathbf x = mathbf x_texta mathbf x_textm^T. The state vector comprises two components:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"mathbf x_texta in mathbbR^n-1, which holds the bus voltage angles of demand and generator buses, represented by mathbf x_texta = theta_i, where i in mathcalN_textpq cup mathcalN_textpv,\nmathbf x_textm in mathbbR^n_textpq, which holds the bus voltage magnitudes of demand buses, represented by mathbf x_textm = V_i, where i in mathcalN_textpq, and n_textpq = mathcalN_textpq.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Knowing the voltage magnitudes and angles for certain types of buses is a consequence of the structure of the state vector mathbf x. Specifically, the voltage magnitude and angle at the slack bus are known, as well as the voltage magnitude at generator buses.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As detailed in the Nodal Network Equations section of this manual, the expressions for active and reactive power injection are as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n P_i =V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j\n Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Using the above equations, we can define the active power injection function for demand and generator buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - P_i = 0\n forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"and the reactive power injection function for demand buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - Q_i = 0\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The active and reactive mismatches, often denoted as Delta P_i(mathbf x) and Delta Q_i(mathbf x), respectively, are defined as the functions f_P_i(mathbf x) and f_Q_i(mathbf x). The first terms on the right-hand side represent power injections at a bus, while the second term is constant and is obtained based on the active and reactive powers of the generators that supply a bus and active and reactive powers demanded by consumers at the same bus. Therefore, the Newton-Raphson method solves the system of nonlinear equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbff(x) =\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where the first n - 1 equations correspond to demand and generator buses, and the last n_textpq equations correspond to demand buses.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To compute the voltage magnitudes and angles of buses using the Newton-Raphson method in JuliaGrid, you must first execute the acModel! function to set up the system, followed by initializing the Newton-Raphson method using the newtonRaphson function. The following code snippet demonstrates this process:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This results in the creation of the starting vectors of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0), as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, we utilize a \"flat start\" approach in our method. It is important to keep in mind that when dealing with initial conditions in this manner, the Newton-Raphson method may encounter difficulties.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To implement the Newton-Raphson method, the iterative approach based on the Taylor series expansion, JuliaGrid provides the mismatch! and solve! functions. These functions are utilized to carry out the Newton-Raphson method iteratively until a stopping criterion is reached, as demonstrated in the following code snippet:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The mismatch! function calculates the mismatch in active power injection for demand and generator buses and the mismatch in reactive power injection for demand buses at each iteration nu = 1 2 dots. The equations used for these computations are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x^(nu-1)) = V_i^(nu-1)sumlimits_j=1^n (G_ijcostheta_ij^(nu-1)+B_ijsintheta_ij^(nu-1))V_j^(nu-1) - P_i\n forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"as well as the reactive power injection mismatch for demand buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x^(nu-1)) = V_i^(nu)sumlimits_j=1^n (G_ijsintheta_ij^(nu-1)-B_ijcostheta_ij^(nu-1))V_j^(nu-1) - Q_i\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting vector from these calculations is stored in the mismatch variable of the ACPowerFlow abstract type and can be accessed through the following line of code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐟 = analysis.method.mismatch","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In addition to computing the mismatches in active and reactive power injection, the mismatch! function also returns the maximum absolute values of these mismatches. These maximum values are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max f_P_i(mathbf x^(nu-1)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max f_Q_i(mathbf x^(nu-1)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the function solve! computes the increments of bus voltage angle and magnitude at each iteration using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfDelta mathbfx^(nu-1) = -mathbfJ(mathbfx^(nu-1))^-1 mathbff(mathbfx^(nu-1))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where mathbfDelta mathbfx = mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm^T consists of the vector of bus voltage angle increments mathbf Delta mathbf x_texta in mathbbR^n-1 and bus voltage magnitude increments mathbf Delta mathbf x_textm in mathbbR^n_textpq, and mathbfJ(mathbfx) in mathbbR^n_textu times n_textu is the Jacobian matrix, n_textu = n + n_textpq - 1.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing the Jacobian matrix mathbfJ = mathbfLmathbfU, aiming to compute the increments. Nevertheless, users have the flexibility to opt for QR factorization as an alternative method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These values are stored in the ACPowerFlow abstract type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱 = analysis.method.increment\n𝐉 = analysis.method.jacobian\n𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The JuliaGrid implementation of the AC power flow follows a specific order to store the increment mathbfDelta mathbfx and mismatch mathbff(x) vectors. The first n-1 elements of both vectors correspond to the demand and generator buses in the same order as they appear in the input data. The first n-1 elements of the increment vector mathbfDelta mathbfx correspond to the voltage angle increments mathbf Delta mathbf x_texta, while the first n-1 elements of the mismatch vector mathbff(x) correspond to the mismatch in active power injections mathbff_textP(mathbf x).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The last n_textpq elements of the increment mathbfDelta mathbfx and mismatch mathbff(x) vectors correspond to the demand buses in the order they appear in the input data. For the increment vector mathbfDelta mathbfx, it matches the bus voltage magnitude increments mathbf Delta mathbf x_textm, while for the mismatch vector mathbff(x), it matches the mismatch in reactive power injections mathbff_textQ(mathbf x).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These specified orders dictate the row and column order of the Jacobian matrix mathbfJ(mathbfx).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Finally, the function solve! adds the computed increment term to the previous solution to obtain a new solution:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x^(nu) = mathbf x^(nu-1) + mathbf Delta mathbf x^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The bus voltage magnitudes mathbfV = V_i and angles bmTheta = theta_i are then updated based on the obtained solution mathbf x. It is important to note that only the voltage magnitudes related to demand buses and angles related to demand and generator buses are updated; not all values are updated. Therefore, the final solution obtained by JuliaGrid is stored in the following vectors:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Jacobian-Matrix","page":"AC Power Flow","title":"Jacobian Matrix","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To complete the tutorial on the Newton-Raphson method, we will now describe the Jacobian matrix and provide the equations involved in its evolution. Without loss of generality, we assume that the slack bus is the first bus, followed by the set of demand buses and the set of generator buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathcalN_textsb = 1 \n mathcalN_textpq = 2 dots m \n mathcalN_textpv = m + 1dots n\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where mathcalN = mathcalN_textsb cup mathcalN_textpq cup mathcalN_textpv. Therefore, we can express:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbf x_texta = theta_2dotstheta_n^T mathbf Delta mathbf x_texta = Delta theta_2dotsDelta theta_n^T \n mathbf x_textm = V_2dotsV_m^T mathbf Delta mathbf x_textm = Delta V_2dotsDelta V_m^T\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Jacobian matrix mathbfJ(x^(nu)) in mathbbR^n_textu times n_textu is:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfJ(x^(nu))=\n left\n beginarraycccccc\n cfracmathrm partialf_P_2(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial V_m\n vdots \n cfracmathrm partialf_P_n(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial V_m 10pt\n hline \n cfracmathrm partialf_Q_2(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial V_m\n vdots \n cfracmathrm partialf_Q_m(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial V_m\n endarray\n right","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Jacobian matrix can be expressed using four block matrices:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"\tmathbfJ(x^(nu)) =\n beginbmatrix\n mathbfJ_11(x^(nu)) mathbfJ_12(x^(nu)) mathbfJ_21(x^(nu)) \n\t mathbfJ_22(x^(nu))\n endbmatrix","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where diagonal elements of the Jacobian sub-matrices are defined as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x^(nu)) mathrm partial theta_i =\n V_i^(nu)sumlimits_j=1^n (-G_ijsintheta_ij^(nu)+B_ijcostheta_ij^(nu))V_j^(nu) - B_ii(V_i^(nu))^2\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial V_i^(nu) =\n sumlimits_j=1^n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_j^(nu) + G_iiV_i^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu)) mathrm partial theta_i =\n V_i^(nu) sumlimits_j=1^n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_j^(nu) - G_ii(V_i^(nu))^2\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrm partial V_i =\n sumlimits_j=1^n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_j^(nu) - B_iiV_i^(nu)\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"while non-diagonal elements of the Jacobian sub-matrices are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial theta_j =\n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_i^(nu)V_j^(nu)\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial V_j^(nu) =\n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_i^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrm partial theta_j =\n -(G_ijcostheta_ij^(nu) + B_ijsintheta_ij^(nu))V_i^(nu)V_j^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrmpartial V_j =\n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_i^(nu)\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#FastNewtonRaphsonMethodTutorials","page":"AC Power Flow","title":"Fast Newton-Raphson Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Although the fast Newton-Raphson method may converge more slowly than the traditional Newton-Raphson method, the shorter solution time for the updates often compensates for this slower convergence, resulting in a shorter overall solution time. This is particularly true for systems that are not heavily loaded, where a shorter overall solution time is almost always achieved. It is important to note that if the algorithm converges, it will converge to a correct solution [6].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The fast Newton-Raphson method involves decoupling the power flow equations. Namely, the Newton-Raphson method is based on the equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginbmatrix\n mathbfJ_11(x) mathbfJ_12(x) mathbfJ_21(x) \n\t mathbfJ_22(x)\n endbmatrix\n beginbmatrix\n mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm\n endbmatrix\t+\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where the iteration index has been omitted for simplicity. However, in transmission grids, there exists a strong coupling between active powers and voltage angles, as well as between reactive powers and voltage magnitudes. To achieve decoupling, two conditions must be satisfied: first, the resistance values r_ij of the branches must be small compared to their reactance values x_ij, and second, the angle differences must be small, i.e., theta_ij approx 0 [10]. Therefore, starting from the above equation, we have:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginbmatrix\n mathbfJ_11(x) mathbf0 mathbf0 mathbfJ_22(x)\n endbmatrix\n beginbmatrix\n mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm\n endbmatrix\t+\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"which gives the decoupled system as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbff_textP(mathbf x) = -mathbfJ_11(x) mathbf Delta mathbf x_texta \n mathbff_textQ(mathbf x) = -mathbfJ_22(x) mathbf Delta mathbf x_textm\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To examine the problem, it is helpful to express it as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = -Delta theta_2cfracmathrm partialf_P_2(mathbf x) mathrm partial theta_2 - cdots -\n Delta theta_n cfracmathrm partialf_P_2(mathbf x)mathrm partial theta_n \n vdots \n f_P_n(mathbf x) = -Delta theta_2cfracmathrm partialf_P_n(mathbf x) mathrm partial theta_2 - cdots -\n Delta theta_n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_n\n f_Q_2(mathbf x) = - Delta V_2 cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_2 - cdots -\n Delta V_n_textpq cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_m\n vdots \n f_Q_m(mathbf x) = - Delta V_2 cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_2 - cdots -\n Delta V_m cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Firstly, the second part of the expressions is expanded as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_Q_2(mathbf x) =\n -cfracDelta V_2V_2V_2 cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_2 - cdots -\n cfracDelta V_mV_m V_m\n cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_m\n vdots \n f_Q_m(mathbf x) =\n - cfracDelta V_2V_2V_2 cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_2 - cdots -\n cfracDelta V_mV_m V_m\n cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the Jacobian elements are derived. To achieve this, we can use the expressions defined for the Newton-Raphson method. For demand buses, the above expansions are applied as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i =\n V_isumlimits_j=1^n (-G_ijsintheta_ij+B_ijcostheta_ij)V_j - B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_iV_j\n V_i cfracmathrm partialf_Q_i(mathbf x)mathrm partial V_i =\n V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - B_iiV_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j =\n (G_ijsintheta_ij-B_ijcostheta_ij) V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As the definition of reactive power is given by the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"the Jacobian elements can be expressed in the following manner:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i =\n -Q_i - B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij) V_i V_j\n V_i cfracmathrm partialf_Q_i(mathbf x)mathrm partial V_i =\n Q_i - B_ii V_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j =\n (G_ijsintheta_ij - B_ijcostheta_ij) V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The decoupled model is established through the following approximations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n sin(theta_ij) approx 0 \n cos(theta_ij) approx 1 \n Q_i B_iiV_i^2\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, when the approximations are made, the Jacobian elements are simplified, resulting in the decoupled model where the Jacobian elements are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i = -B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_j = -B_ijV_iV_j\n V_i cfracmathrm partialf_Q_i(mathbf x) mathrm partial V_i = -B_iiV_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j = -B_ijV_iV_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, the initial system of equations becomes:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = B_22 Delta theta_2 V_2^2 + cdots + B_2n Delta theta_n V_2V_n \n vdots \n f_P_n(mathbf x) = B_n2 Delta theta_2 V_2V_n + cdots + B_nn Delta theta_n V_n^2 \n f_Q_2(mathbf x) = B_22 cfracDelta V_2V_2 V_2^2 + cdots + B_2m cfracDelta V_mV_m V_2V_m \n vdots \n f_Q_m(mathbf x) = B_m2 cfracDelta V_2V_2 V_2V_m + cdots + B_mm cfracDelta V_mV_m V_m^2\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Using V_j approx 1, wherein V_i^2 = V_iV_j j=i, the first part of the equations can be simplified to:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = B_22 Delta theta_2 V_2 + cdots + B_2n Delta theta_n V_2\n vdots \n f_P_n(mathbf x) = B_n2 Delta theta_2 V_n + cdots + B_nn Delta theta_n V_n\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, the second part of the equations can be simplified to:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_Q_2(mathbf x) = B_22 V_2 Delta V_2 + cdots + B_2m V_2 Delta V_m\n \n vdots \n f_Q_m(mathbf x) = B_m2 V_m Delta V_2 + cdots + B_mm V_m Delta V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The fast Newton-Raphson method is ultimately based on the system of equations presented below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracf_P_2(mathbf x)V_2 = B_22 Delta theta_2 + cdots + B_2n Delta theta_n \n vdots \n cfracf_P_n(mathbf x)V_n = B_n2 Delta theta_2 + cdots + B_nn Delta theta_n \n cfracf_Q_2(mathbf x)V_2 = B_22 Delta V_2 + cdots + B_2m Delta V_m \n vdots \n cfracf_Q_m(mathbf x)V_m = B_m2 Delta V_2 + cdots +\n B_mm Delta V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This system can be written as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbfh_textP(mathbf x) = mathbfB_1 mathbf Delta mathbf x_texta \n mathbfh_textQ(mathbf x) = mathbfB_2 mathbf Delta mathbf x_textm\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"One of the main advantages of this approach is that the Jacobian matrices mathbfB_1 and mathbfB_2 are constant and need only be formed once. Furthermore, this method can be used to define both the XB and BX versions of the fast Newton-Raphson method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#XB-Version","page":"AC Power Flow","title":"XB Version","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The matrix mathbfB_1 is formed by neglecting the resistance r_ij, shunt susceptance Im y_textshi , charging susceptance Im y_textsij , and transformer tap ratio magnitude tau_ij. The matrix mathbfB_2 is constructed by disregarding the transformer phase shift angle phi_ij. This approach corresponds to the standard fast Newton-Raphson method and is known to exhibit exceptional convergence properties in typical scenarios [10].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To initialize the XB version of the fast Newton-Raphson method, one can utilize the following code snippet:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = fastNewtonRaphsonXB(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#BX-Version","page":"AC Power Flow","title":"BX Version","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The matrix mathbfB_1 ignores the shunt susceptanceIm y_textshi , charging susceptance Im y_textsij , and transformer tap ratio magnitude tau_ij. The matrix mathbfB_2 ignores the resistance r_ij and transformer phase shift angle phi_ij. In usual cases, the iteration count for the BX version is comparable to the XB scheme. However, for systems with high r_ijx_ij ratios, the BX scheme requires considerably fewer iterations than the XB scheme to solve the power flow [10].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To initialize the BX version of the fast Newton-Raphson method, you can use the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = fastNewtonRaphsonBX(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization-2","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"When a user creates the fast Newton-Raphson method in JuliaGrid, the Jacobian matrices mathbfB_1 and mathbfB_2 are formed to correspond to the active and reactive power equations, respectively:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐁₁ = analysis.method.active.jacobian\n𝐁₂ = analysis.method.reactive.jacobian","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, during this stage, JuliaGrid generates the starting vectors for bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0) as demonstrated below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process-2","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the mismatch! and solve! functions to implement the fast Newton-Raphson method iterations. These functions are used iteratively until a stopping criterion is met, as shown in the code snippet below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The functions mathbff_textP(mathbf x) and mathbff_textQ(mathbf x) remain free of approximations, with only the calculation of the state variable increments affected [6]. As a result, we still use the following equations to compute the mismatches:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_i(mathbf x) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - P_i = 0\n forall i in mathcalN_textpq cup mathcalN_textpv\n f_Q_i(mathbf x) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - Q_i = 0\n forall i in mathcalN_textpq\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Therefore, the mismatch! function calculates the mismatch in active power injection for demand and generator buses and the mismatch in reactive power injection for demand buses at each iteration nu = 1 2 dots:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n h_P_i(mathbf x^(nu-1)) =\n sumlimits_j=1^n (G_ijcostheta_ij^(nu-1)+B_ijsintheta_ij^(nu-1))V_j^(nu-1) - cfracP_iV_i^(nu-1)\n forall i in mathcalN_textpq cup mathcalN_textpv \n h_Q_i(mathbf x^(nu-1)) =\n sumlimits_j=1^n (G_ijsintheta_ij^(nu-1)-B_ijcostheta_ij^(nu-1))V_j^(nu-1) - cfracQ_iV_i^(nu-1)\n forall i in mathcalN_textpq\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting vectors from these calculations are stored in the ACPowerFlow abstract type and can be accessed through the following:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐡ₚ = analysis.method.active.increment\n𝐡ₒ = analysis.method.reactive.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In addition to computing the mismatches in active and reactive power injection, the mismatch! function also returns the maximum absolute values of these mismatches. These maximum values are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max h_P_i(mathbf x^(nu)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max h_Q_i(mathbf x^(nu)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the function solve! computes the bus voltage angle increments:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf Delta mathbf x_texta^(nu-1) = mathbfB_1^-1 mathbfh_textP(mathbf x^(nu-1))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the voltage angle increments, JuliaGrid initially performs LU factorization on the Jacobian matrix mathbfB_1 = mathbfL_1mathbfU_1. This factorization is executed only once and is utilized in each iteration of the algorithm:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐋₁ = analysis.method.active.factorization.L\n𝐔₁ = analysis.method.active.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing Jacobian matrix. Nevertheless, users have the flexibility to opt for QR factorization as an alternative method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vector of increments that corresponds to the active power equations can be accessed using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱ₐ = analysis.method.active.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The solution is then updated as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x_texta^(nu) = mathbf x_texta^(nu-1) + mathbf Delta mathbf x_texta^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"It is important to note that only the voltage angles related to demand and generator buses are updated, while the vector of bus voltage angles of all buses is stored:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After calculating the update for voltage angles, to calculate the magnitude updates the fast Newton-Raphson method then solves the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf Delta mathbf x_textm^(nu-1) = mathbfB_2^-1 mathbfh_textQ(mathbf x^(nu))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly to the previous instance, JuliaGrid initially executes LU factorization on the Jacobian matrix mathbfB_2 = mathbfL_2mathbfU_2. However, it provides the flexibility for users to opt for QR factorization instead. This factorization occurs only once and is utilized in each iteration of the fast Newton-Raphson algorithm:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐋₂ = analysis.method.reactive.factorization.L\n𝐔₂ = analysis.method.reactive.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vector of increments that corresponds to the reactive power equations can be accessed using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱ₘ = analysis.method.active.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Finally, the solution is updated as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x_textm^(nu) = mathbf x_textm^(nu-1) + mathbf Delta mathbf x_textm^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Again, it is important to note that only the voltage magnitudes of demand buses are updated, while the vector of bus voltage magnitude for all buses is stored:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GaussSeidelMethodTutorials","page":"AC Power Flow","title":"Gauss-Seidel Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As elaborated in the Nodal Network Equations section of this manual, each bus is associated with the balance equation expressed as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" sum_j = 1^n Y_ij bar V_j = cfracP_i - textjQ_ibarV_i forall i in mathcalN","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In its expanded form, this can be written as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n Y_11 barV_1 + cdots+ Y_1nbarV_n = fracP_1 - jQ_1barV_1^* \n vdots \n Y_n1 barV_1 + cdots+ Y_nnbarV_n = fracP_n - jQ_nbarV_n^*\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"While the Gauss-Seidel method directly solves the system of equations, it suffers from very slow convergence, which increases almost linearly with the system size, necessitating numerous iterations to obtain the desired solution [11]. Moreover, the convergence time of the Gauss-Seidel method increases significantly for large-scale systems and can face convergence issues for systems with high active power transfers. Nevertheless, power flow programs utilize both the Gauss-Seidel and Newton-Raphson methods in a complementary manner. Specifically, the Gauss-Seidel method is employed to obtain a quick approximate solution from a \"flat start\", while the Newton-Raphson method is utilized to obtain the final accurate solution [8].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Gauss-Seidel method is usually applied to a system of n complex equations, where one represents the slack bus. Consequently, one equation can be eliminated, resulting in a power flow problem with n-1 equations.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization-3","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid provides a way to utilize the Gauss-Seidel method for solving the AC power flow problem and determining the magnitudes and angles of bus voltages. To use this method, we need to execute the acModel! function first to set up the system and then initialize the Gauss-Seidel method using the gaussSeidel function. The code snippet below demonstrates this process:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = gaussSeidel(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This results in the creation of the starting vectors of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0), as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process-3","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the mismatch! and solve! functions to implement the Gauss-Seidel method iterations. These functions are used iteratively until a stopping criterion is met, as shown in the code snippet below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:300\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In contrast to the Newton-Raphson and fast Newton-Raphson methods, the Gauss-Seidel method does not require the calculation of the mismatch in active and reactive power injection at each iteration. Instead, the mismatch! function is used solely to verify the convergence criteria. At each iteration nu = 1 2 dots, we calculate the active power injection mismatch for demand and generator buses, as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x^(nu-1)) = RebarV_i^(nu - 1) barI_i^*(nu - 1) - P_i forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We also compute the reactive power injection mismatch for demand buses, given by:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x^(nu-1)) = ImbarV_i^(nu - 1) barI_i^*(nu - 1) - Q_i forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"However, these mismatches are not stored, as they are only used to obtain the maximum absolute values of these mismatches. The maximum values of these mismatches are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon, as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max f_P_i(mathbf x^(nu-1)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max f_Q_i(mathbf x^(nu-1)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After initializing complex bus voltages barV_i^(0) for all buses in the power system, the function solve! proceeds to compute the voltages for demand buses using the Gauss-Seidel method:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barV_i^(nu) =\n cfrac1Y_ii Bigg(cfracP_i - jQ_ibarV_i^*(nu-1) -\n sumlimits_substackj = 1^i - 1 Y_ijbarV_j^(nu) -\n sumlimits_substackj = i + 1^n Y_ijbarV_j^(nu-1)Bigg)\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The next step is to determine the solution for generator buses in two stages: first, the reactive power injection is calculated, and then the bus complex voltage is updated using the following equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n Q_i^(nu) =\n -Im left barV_i^*(nu) sumlimits_j=1^n Y_ijbarV_j^(nu)right forall i in mathcalN_textpv \n barV_i^(nu ) =\n cfrac1Y_ii Bigg(cfracP_i - jQ_i^(nu)barV_i^*(nu )-\n sumlimits_substackj = 1j neq i^n Y_ijbarV_j^(nu) Bigg) forall i in mathcalN_textpv\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The obtained voltage magnitude may not be equal to the magnitude specified for the generator bus, so a voltage correction step is necessary:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barV_i^(nu) = V_i^(0) cfracbarV_i^(nu)V_i^(nu) forall i in mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid stores the final results in vectors that contain all bus voltage magnitudes and angles:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#ACPowerAnalysisTutorials","page":"AC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses, branches, and generators. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses, branches, and generators:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Generator Active Reactive\nOutputs mathbfP_textg = P_textgi mathbfQ_textg = Q_textgi","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-Injections","page":"AC Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GeneratorPowerInjectionsManual","page":"AC Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The power! function in JuliaGrid also computes the active and reactive power injections from the generators at each bus. The active power supplied by the generators to the buses can be calculated by summing the given generator active powers in the input data, except for the slack bus, which can be determined as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" P_textpi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textdi represents the active power demanded by consumers at the slack bus. The active power injections from the generators at each bus are stored as the vector, denoted by mathbfP_textp = P_textpi, can be obtained using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The calculation of reactive power injection from the generators at generator or slack buses can be achieved using the subsequent equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_textpi = Q_i + Q_textdi forall i in mathcalN_textpv cup mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where Q_textdi represents the reactive power demanded by consumers at the corresponding bus. Further, the reactive power injected by the generators at buses from mathcalN_textpq can be calculated by summing the given generator reactive powers in the input data. The vector of these reactive power injections by the generators to the buses, denoted by mathbfQ_textp = Q_textpi, can be retrieved using the following command:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Bus-Shunt-Elements","page":"AC Power Flow","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-Flows","page":"AC Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Branch-Shunt-Elements","page":"AC Power Flow","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Branch-Series-Elements","page":"AC Power Flow","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GeneratorPowerOutputsManual","page":"AC Power Flow","title":"Generator Power Outputs","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the output active powers of each generator connected to bus i in mathcalN_textpq cup mathcalN_textpv, the given active power in the input data is utilized. For the generator connected to the slack bus, the output active power is determined using the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" P_textgi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In the case of multiple generators connected to the slack bus, the first generator in the input data is assigned the obtained value of P_textgi. Then, this amount of power is reduced by the output active power of the other generators.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To retrieve the vector of active power outputs of generators, denoted as mathbfP_textg = P_textgi, i in mathcalS, where the set mathcalS represents the set of generators, users can utilize the following command:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The output reactive powers of each generator located at the bus is obtained as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_textgi = Q_i + Q_textdi i in mathcalN","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"If there are multiple generators at the same bus, the reactive power is allocated proportionally among the generators based on their reactive power capabilities.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To retrieve the vector of reactive power outputs of generators, denoted as mathbfQ_textg = Q_textgi, i in mathcalS, users can utilize:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐐ₒ = analysis.power.generator.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#ACCurrentAnalysisTutorials","page":"AC Power Flow","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-Injections","page":"AC Power Flow","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-Flows","page":"AC Power Flow","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-at-Branch-Series-Elements","page":"AC Power Flow","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowTutorials","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, HiGHS\n@default(template) # hide\n@default(unit) # hide\n\n@labels(Integer)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, angle = 0.17)\naddBus!(system; label = 2, type = 2, active = 0.1, conductance = 0.04)\naddBus!(system; label = 3, type = 1, active = 0.05)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.05, maxFromBus = 0.15)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.01, maxFromBus = 0.10)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.01, maxFromBus = 0.25)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = 1, bus = 1, active = 3.2, maxActive = 0.5)\naddGenerator!(system; label = 2, bus = 2, active = 0.2, maxActive = 0.3)\n\ncost!(system; label = 1, active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = 2, active = 1, piecewise = [10.85 12.3; 14.77 16.8; 18 18.1])\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Moreover, we identify the set of generators as mathcalS = 1 dots n_textg within the power system:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝒮 = collect(keys(system.generator.label))","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or generator i in mathcalS, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowModelTutorials","page":"DC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the DC optimal power flow, the active power outputs of the generators mathbf P_textg = P_textgi, i in mathcalS, are represented as linear functions of the bus voltage angles bmTheta = theta_i, i in mathcalN. Thus, the optimization variables in this model are the active power outputs of the generators and the bus voltage angles.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow model has the form:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n textminimize sum_i in mathcalS f_i(P_textgi) \n textsubjectto theta_i - theta_texts = 0 i in mathcalN_textsb 3pt\n h_P_i(mathbf P_textg bmTheta) = 0 forall i in mathcalN 3pt\n theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE 3pt\n P_ij^textmin leq h_P_ij(theta_i theta_j) leq P_ij^textmax forall (ij) in mathcalE 3pt\n P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Essentially, the DC optimal power flow is focused on the minimization of the objective function related to the costs associated with the active power output of generators, all while ensuring the satisfaction of various constraints. This optimization task holds a crucial role in the efficient and timely management of electrical power systems. However, it is important to note that the solutions provided by the DC optimal power flow are approximate in nature.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Build-Optimal-Power-Flow-Model","page":"DC Optimal Power Flow","title":"Build Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To build the DC optimal power flow model, we must first load the power system and establish the DC model using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Afterward, the DC optimal power flow model is created using the dcOptimalPowerFlow function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer; active = \"Pg\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Optimization-Variables","page":"DC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Hence, the variables in this model encompass the active power outputs of the generators denoted as mathbfP_textg = P_textgi, where i in mathcalS, and the bus voltage angles represented by bmTheta = theta_i, where i in mathcalN. You can access these variables using the following:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = analysis.method.variable.active\n𝚯 = analysis.method.variable.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Objective-Function","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The objective function represents the sum of the active power cost functions f_i(P_textgi), i in mathcalS, for each generator, where these cost functions can be polynomial or linear piecewise functions. It is important to note that only polynomial cost functions up to the second degree are included in the objective function. If higher-degree polynomials are present, they will be excluded from the objective function by JuliaGrid.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Polynomial-Active-Power-Cost-Function","page":"DC Optimal Power Flow","title":"Polynomial Active Power Cost Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow in JuliaGrid allows the cost function f_i(P_textgi) to be represented as a polynomial of up to the second degree, making it possible to express the cost function as linear or quadratic. The possible representations are as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n f_i(P_textgi) = a_1P_textgi + a_0 \n f_i(P_textgi) = a_2 P_textgi^2 + a_1P_textgi + a_0\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Furthermore, it is worth noting that the function can be given simply as a constant with only the coefficient a_0, which implies that the cost of the generator remains constant regardless of the active power outputs. In conclusion, as illustrated in Figure 1, typical scenarios involve linear or quadratic cost functions, resulting in a best-case scenario for a linear optimization problem and a worst-case scenario for a quadratic optimization problem.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"\n
Figure 1: The polynomial cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"When utilizing the cost! function within JuliaGrid, employing the polynomial keyword results in the polynomial being constructed with coefficients ordered from the highest degree to the lowest. For instance, in the provided case study, we created a quadratic polynomial represented as:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n f_1(P_textg1) = 11002 P_textg1^2 + 500 P_textg1 + 80\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To access these coefficients, users can utilize the variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"f₁ = system.generator.cost.active.polynomial[1]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Linear-Piecewise-Active-Power-Cost-Function","page":"DC Optimal Power Flow","title":"Linear Piecewise Active Power Cost Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow in JuliaGrid offers another option for defining cost functions by using linear piecewise functions as approximations of the polynomial functions, as depicted in Figure 2.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"\n
Figure 2: The linear piecewise cost functions of active power output.
\n ","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To define linear piecewise functions in JuliaGrid, users can utilize the cost! function with the piecewise keyword. The linear piecewise function is constructed using a matrix where each row defines a single point. The first column holds the generator's active power output, while the second column corresponds to the associated cost value. For example, in the provided case study, a linear piecewise function is created and can be accessed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"f₂ = system.generator.cost.active.piecewise[2]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similar to how convex linear piecewise functions are treated in the AC Optimal Power Flow, JuliaGrid adopts a constrained cost variable method for the linear piecewise functions. In this method, the piecewise linear cost function is converted into a series of linear inequality constraints for each segment, which are defined by two adjacent points along the line, along with a helper variable specific to the piecewise function. However, for linear piecewise functions that have only one segment defined by two points, JuliaGrid simplifies it into a standard linear function without requiring a helper variable.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Consequently, for a piecewise cost function denoted as f_i(P_textgi) with k segments (where k 1), the j-th segment, defined by the points P_textgij f_i(P_textgij) and P_textgij+1 f_i(P_textgij+1), is characterized by the following inequality constraints:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"cfracf_i(P_textgij+1) - f_i(P_textgij)P_textgij+1 - P_textgij(P_textgi - P_textgij) + f_i(P_textgij) leq H_i i in mathcalS j = 1dotsk","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where H_i represents the helper variable. To finalize this method, we simply need to include the helper variable H_i in the objective function. This approach efficiently handles linear piecewise cost functions, providing the flexibility to capture nonlinear characteristics while still benefiting from the advantages of linear optimization techniques.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As an example, in the provided case study, the helper variable is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"H₂ = analysis.method.variable.actwise[2]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Lastly, the set of constraints introduced by the linear piecewise cost function is displayed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.piecewise.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Objective-Function-2","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As previously explained, the objective function relies on the defined polynomial or linear piecewise cost functions and represents the sum of these costs. In the provided example, the objective function that must be minimized to obtain the optimal values for the active power output of the generators and the bus voltage angles can be accessed using the following code:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Constraint-Functions","page":"DC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the following section, we will examine the various constraints defined within the DC optimal power flow model.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Slack-Bus-Constraint","page":"DC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The first equality constraint is linked to the slack bus, where the bus voltage angle denoted as theta_i is fixed to a constant value theta_texts. It can be expressed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"theta_i - theta_texts = 0 i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where the set mathcalN_textsb contains the index of the slack bus. To access the equality constraint from the model, we can utilize the variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.slack.angle)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Bus-Active-Power-Balance-Constraints","page":"DC Optimal Power Flow","title":"Bus Active Power Balance Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The second equality constraint in the optimization problem is associated with the active power balance equation:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_i(mathbf P_textg bmTheta) = 0 forall i in mathcalN","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As elaborated in the Nodal Network Equations section, we can express the equation as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_i(mathbf P_textg bmTheta) = sum_k in mathcalS_i P_textgk - sum_k = 1^n B_ik theta_k - P_textdi - P_textshi - P_texttri","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this equation, the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN, and P_textgk represents the active power output of the k-th generator within the set mathcalS_i. More precisely, the variable P_textgk represents the optimization variable, as well as the bus voltage angle theta_k.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The constant terms in these equations are determined by the active power demand at bus P_textdi, the active power demanded by the shunt element P_textshi, and power related to the shift angle of the phase transformers P_texttri. The values representing these constant terms mathbfP_textd = P_textdi, mathbfP_textsh = P_textshi, and mathbfP_texttr = P_texttri, i in mathcalN, can be accessed:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = system.bus.demand.active\n𝐏ₛₕ = system.bus.shunt.conductance\n𝐏ₜᵣ = system.model.dc.shiftPower","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.balance.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Bus-Voltage-Angle-Difference-Constraints","page":"DC Optimal Power Flow","title":"Bus Voltage Angle Difference Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraint related to the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where theta_ij^textmin represents the minimum, while theta_ij^textmax represents the maximum of the angle difference between adjacent buses. The values representing the voltage angle difference, denoted as bmTheta_textlm = theta_ij^textmin theta_ij^textmax, (ij) in mathcalE, are provided as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝚯ₗₘ = [system.branch.voltage.minDiffAngle system.branch.voltage.maxDiffAngle]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.angle)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Branch-Active-Power-Flow-Constraints","page":"DC Optimal Power Flow","title":"Branch Active Power Flow Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraint related to active power flow is used to represent thermal limits on power transmission. This constraint is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"P_ij^textmin leq h_P_ij(theta_i theta_j) leq P_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The branch flow limits at the from-bus, denoted as mathbfP_textf = P_ij^textmin P_ij^textmax , can be retrieved as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = [system.branch.flow.minFromBus system.branch.flow.maxFromBus]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The active power flow at branch (ij) in mathcalE can be derived using the Branch Network Equations and is given by:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_ij(theta_i theta_j) = frac1tau_ij x_ij (theta_i - theta_j - phi_ij)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.flow.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Generator-Active-Power-Capability-Constraints","page":"DC Optimal Power Flow","title":"Generator Active Power Capability Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraints associated with the minimum and maximum active power outputs of the generators are defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this representation, the lower and upper bounds are determined by the vector mathbfP_textm = P_textgi^textmin P_textgi^textmax, i in mathcalS. We can access these bounds using the following variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₘ = [system.generator.capability.minActive system.generator.capability.maxActive]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.capability.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowSolutionTutorials","page":"DC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To acquire the output active power of generators and the bus voltage angles, the user must invoke the function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Therefore, to get the vector of output active power of generators mathbfP_textg = P_textgi, i in mathcalS, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Further, the resulting bus voltage angles bmTheta = theta_i, i in mathcalN, are saved in the vector as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerAnalysisTutorials","page":"DC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution from the DC optimal power flow, we can calculate the powers related to buses and branches using the power! function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Power-Injections","page":"DC Optimal Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Generator-Power-Injections","page":"DC Optimal Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The active power supplied by generators to the buses can be calculated by summing the active power outputs of the generators obtained from the optimal DC power flow. This can be expressed as:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":" P_textpi = sum_k=1^n_textgi P_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Here, P_textgk represents the active power output of the k-th generator connected to bus i in mathcalN, and n_textgi denotes the total number of generators connected to the same bus. We can obtain the vector of active powers injected by generators into the buses, denoted as mathbfP_textp = P_textpi, using the following command:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Power-Flows","page":"DC Optimal Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The resulting from-bus active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similarly, the resulting to-bus active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"manual/pmuStateEstimation/#PMUStateEstimationManual","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To perform linear state estimation solely based on PMU data, the initial requirement is to have the PowerSystem type configured with the AC model, along with the Measurement type storing measurement data. Subsequently, we can formulate either the weighted least-squares (WLS) or the least absolute value (LAV) PMU state estimation model encapsulated within the type PMUStateEstimation using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"pmuStateEstimation,\npmuLavStateEstimation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For resolving the PMU state estimation problem and obtaining bus voltage magnitudes and angles, utilize the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After executing the function solve!, where the user employs the WLS method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Moreover, before the creating PMUStateEstimation type, users can initiate an optimal PMU placement algorithm to determine the minimal set of PMUs required for an observable system:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"pmuPlacement.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After obtaining the PMU state estimation solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses and branches:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses or branches.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#OptimalPMUPlacementManual","page":"PMU State Estimation","title":"Optimal PMU Placement","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us define the PowerSystem type and perform the AC power flow analysis solely for generating data to artificially create measurement values:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\n\n@generator(reactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 2.1)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:10\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Optimal-Solution","page":"PMU State Estimation","title":"Optimal Solution","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon defining the PowerSystem type, JuliaGrid provides the possibility to determine the minimal number of PMUs required for system observability using the pmuPlacement function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using GLPK\n\nplacement = pmuPlacement(system, GLPK.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The placement variable contains data regarding the optimal placement of measurements. In this instance, installing a PMU at Bus 2 renders the system observable:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.bus","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This PMU installed at Bus 2 will measure the bus voltage phasor at the corresponding bus and all current phasors at the branches incident to Bus 2 located at the from-bus or to-bus ends:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.from\nplacement.to","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Optimal PMU Placement for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Measurement-Data","page":"PMU State Estimation","title":"Measurement Data","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing PMU placement and AC power flow data, which serves as the source for measurement values in this scenario, we can construct the Measurement type as follows:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\n\n@pmu(label = \"PMU ? (!)\")\nfor (bus, idx) in placement.bus\n Vᵢ, θᵢ = analysis.voltage.magnitude[idx], analysis.voltage.angle[idx]\n addPmu!(system, device; bus = bus, magnitude = Vᵢ, angle = θᵢ)\nend\nfor branch in keys(placement.from)\n Iᵢⱼ, ψᵢⱼ = fromCurrent(system, analysis; label = branch)\n addPmu!(system, device; from = branch, magnitude = Iᵢⱼ, angle = ψᵢⱼ)\nend\nfor branch in keys(placement.to)\n Iⱼᵢ, ψⱼᵢ = toCurrent(system, analysis; label = branch)\n addPmu!(system, device; to = branch, magnitude = Iⱼᵢ, angle = ψⱼᵢ)\nend\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example, we can observe the obtained set of measurement values:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(device.pmu.label, device.pmu.magnitude.mean, device.pmu.angle.mean)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUWLSStateEstimationSolutionManual","page":"PMU State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us continue with the previous example, where we defined the PowerSystem and Measurement types. To establish the PMU state estimation model, we will use the pmuStateEstimation function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the PMU state estimation problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = pmuStateEstimation(system, device, QR)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the bus voltage magnitudes and angles, the solve! function can be invoked as shown:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe recommend that readers refer to the tutorial on PMU State Estimation for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Correlated-Measurement-Errors","page":"PMU State Estimation","title":"Correlated Measurement Errors","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the above approach, we assume that measurement errors from a single PMU are uncorrelated. This assumption leads to the covariance matrix and its inverse matrix (i.e., precision matrix) maintaining a diagonal form:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.precision","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"While this approach is suitable for many scenarios, linear PMU state estimation relies on transforming from polar to rectangular coordinate systems. Consequently, measurement errors from a single PMU become correlated due to this transformation. This correlation results in the covariance matrix, and hence the precision matrix, no longer maintaining a diagonal form but instead becoming a block diagonal matrix.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To accommodate this, users have the option to consider correlation when adding each PMU to the Measurement type. For instance, let us add a new PMU while considering correlation:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 1.01, angle = -0.005, correlated = true)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following this, we recreate the WLS state estimation model:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon inspection, it becomes evident that the precision matrix no longer maintains a diagonal structure:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.precision","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we can address this new scenario and observe the solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Alternative-Formulation","page":"PMU State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"updatePmu!(system, device; label = \"PMU 5 (Bus 3)\", correlated = false)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, by specifying the Orthogonal argument in the pmuStateEstimation function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device, Orthogonal)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Print-Results-in-the-REPL","page":"PMU State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Save-Results-to-a-File","page":"PMU State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nWe also provide functions to print or save state estimation results, such as estimated values and residuals. For more details, users can consult the Power and Current Analysis section of this manual.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUBadDataDetectionManual","page":"PMU State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After acquiring the WLS solution using the solve! function, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new phasor measurement. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 3.2, angle = 0.0, noise = false)\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the PMU state estimation model:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective phasor measurement as out-of-service within the Measurement type.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Moreover, JuliaGrid will adjust the coefficient matrix and mean vector within the PMUStateEstimation type based on measurements now designated as out-of-service. To optimize the algorithm's efficiency, JuliaGrid resets non-zero elements to zero in the coefficient matrix and mean vector, effectively removing the impact of the corresponding measurement on the solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.mean\nanalysis.method.coefficient","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After removing bad data, a new estimate can be computed without considering this specific phasor measurement:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMULAVtateEstimationSolutionManual","page":"PMU State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Setup-Starting-Primal-Values","page":"PMU State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the PMUStateEstimation type. By default, these values are initially established using the initial bus voltage magnitudes and angles from PowerSystem type:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function. It is important to note that JuliaGrid utilizes the provided data to set starting primal values in the rectangular coordinate system.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Solution","page":"PMU State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUMeasurementsAlterationManual","page":"PMU State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the PMUStateEstimation type using the pmuStateEstimation or pmuLavStateEstimation function. Ultimately, resolving the PMU state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.98, angle = -0.023)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 0.5, angle = -0.05)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for the model\nsolve!(system, analysis)\n\naddPmu!(system, device; to = \"Branch 2\", magnitude = 0.5, angle = 3.1)\nupdatePmu!(system, device; label = \"PMU 1\", varianceMagnitude = 1e-8)\nupdatePmu!(system, device; label = \"PMU 3\", statusMagnitude = 0, statusAngle = 0)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for new model\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUStateEstimationUpdateManual","page":"PMU State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"An advanced methodology involves users establishing the PMUStateEstimation type using pmuStateEstimation or pmuLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the PMUStateEstimation type.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where PMUStateEstimation also does not need to be recreated.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of PMUStateEstimation is not practical in terms of reusing the PMUStateEstimation type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can modify the prior example to achieve the same model without establishing PMUStateEstimation twice:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.98, angle = -0.023)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 0.5, angle = -0.05)\naddPmu!(system, device; to = \"Branch 2\", magnitude = 0.5, angle = 3.1, statusAngle = 0)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for the model\nsolve!(system, analysis)\n\nupdatePmu!(system, device, analysis; label = \"PMU 1\", varianceMagnitude = 1e-8)\nupdatePmu!(system, device, analysis; label = \"PMU 3\", statusMagnitude = 0, statusAngle = 0)\nupdatePmu!(system, device, analysis; label = \"PMU 4\", statusAngle = 1)\n\n# <- No need for re-build; we have already updated the existing PMUStateEstimation instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the PMUStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUSEPowerCurrentAnalysisManual","page":"PMU State Estimation","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After obtaining the solution from the PMU state estimation, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the model for which we obtained the PMU state estimation solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, susceptance = 0.002)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.97, angle = -0.051)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 1.66, angle = -0.15)\naddPmu!(system, device; to = \"Branch 2\", magnitude = 1.67, angle = 2.96)\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For instance, if we want to show the active power injections and the from-bus current magnitudes, we can employ the following code:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.magnitude)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nTo better understand the powers and currents associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on PMU State Estimation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Print-Results-in-the-REPL-2","page":"PMU State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can utilize any of the print functions outlined in the Print API. For example, to print state estimation data related to PMUs, we can use:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"@voltage(pu, deg, V)\nshow = Dict(\"Voltage Angle\" => false, \"Current Angle\" => false)\nprintPmuData(system, device, analysis; show)\n@default(unit) # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Save-Results-to-a-CSV-File","page":"PMU State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintPmuData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Injection","page":"PMU State Estimation","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Injection-from-Generators","page":"PMU State Estimation","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Shunt-Element","page":"PMU State Estimation","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Flow","page":"PMU State Estimation","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Charging-Admittances","page":"PMU State Estimation","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Series-Impedance","page":"PMU State Estimation","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Injection","page":"PMU State Estimation","title":"Current Injection","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Flow","page":"PMU State Estimation","title":"Current Flow","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Through-Series-Impedance","page":"PMU State Estimation","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowManual","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To perform the DC power flow, we first need to have the PowerSystem type that has been created with the DC model. Following that, we can construct the power flow model encapsulated within the DCPowerFlow type by employing the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"dcPowerFlow.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To solve the DC power flow problem and acquire bus voltage angles, make use of the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution for DC power flow, JuliaGrid offers a post-processing analysis function to compute active powers associated with buses, branches, and generators:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses, branches, or generators.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCBusTypeModificationManual","page":"DC Power Flow","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"During the initialization process, the designated slack bus, which is initially set, undergoes examination and can be altered using the dcPowerFlow function. Here is an example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 3\")\n\ndcModel!(system)\nanalysis = dcPowerFlow(system)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In this example, the slack bus (type = 3) corresponds to the Bus 1. However, this bus does not have an in-service generator connected to it. JuliaGrid considers this a mistake and attempts to assign a new slack bus from the available generator buses (type = 2) that have connected in-service generators. In this particular example, the Bus 3 will become the new slack bus. As a result, we can observe the updated array of bus types:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; bus = \"Bus 3\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThe bus that is defined as the slack bus (type = 3) but lacks a connected in-service generator will have its type changed to the demand bus (type = 1). Meanwhile, the first generator bus (type = 2) with an in-service generator connected to it will be assigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowSolutionManual","page":"DC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To solve the DC power flow problem using JuliaGrid, we start by creating the PowerSystem type and defining the DC model with the dcModel! function. Here is an example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The dcPowerFlow function can be used to establish the DC power flow problem:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"analysis = dcPowerFlow(system)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the DC power flow problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR, for instance:analysis = dcPowerFlow(system, LDLt)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To obtain the bus voltage angles, we can call the solve! function as follows:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Once the solution is obtained, the bus voltage angles can be accessed using:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nFor implementation insights, we suggest referring to the tutorial on DC Power Flow Analysis.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Print-Results-in-the-REPL","page":"DC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Save-Results-to-a-File","page":"DC Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Save-Results-to-a-CSV-File","page":"DC Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusData(system, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerSystemAlterationManual","page":"DC Power Flow","title":"Power System Update","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After establishing the PowerSystem type using the powerSystem function and configuring the DC model with dcModel!, users gain the capability to incorporate new branches and generators. Furthermore, they can adjust buses, branches, and generators.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Once updates are completed, users can progress towards generating the DCPowerFlow type using the dcPowerFlow function. Ultimately, resolving the DC power flow is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 2.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the defined power system\nsolve!(system, analysis)\n\nupdateBus!(system; label = \"Bus 2\", active = 0.4)\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system; label = \"Branch 1\", status = 0)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.5)\nupdateGenerator!(system; label = \"Generator 1\", active = 1.9)\n\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the updated power system\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate the PowerSystem within the dc field from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowUpdateManual","page":"DC Power Flow","title":"Power Flow Update","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"An advanced methodology involves users establishing the DCPowerFlow type using dcPowerFlow just once. After this initial setup, users can integrate new branches and generators, and also have the capability to modify buses, branches, and generators, all without the need to recreate the DCPowerFlow type.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"This advancement extends beyond the previous scenario where recreating the PowerSystem and DC model was unnecessary, to now include the scenario where DCPowerFlow also does not need to be recreated. Such efficiency can be particularly advantageous in cases where JuliaGrid can reuse nodal matrix factorization.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"By modifying the previous example, we observe that we now create the DCPowerFlow type only once:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 2.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the defined power system\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.4)\n\naddBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system, analysis; label = \"Branch 1\", status = 0)\n\naddGenerator!(system, analysis; label = \"Generator 2\", bus = \"Bus 2\", active = 1.5)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 1.9)\n\n# <- No need for re-build; we have already updated the existing DCPowerFlow instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate both the PowerSystem within the dc field and the DCPowerFlow from the beginning when implementing changes to the existing power system. Additionally, JuliaGrid can reuse symbolic factorizations of LU or LDLt, as long as the nonzero pattern of the nodal matrix remains consistent between power system configurations.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Reusing-Matrix-Factorization","page":"DC Power Flow","title":"Reusing Matrix Factorization","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Drawing from the preceding example, our focus now shifts to finding a solution involving modifications that entail adjusting the active power demand at Bus 2, introducing a new generator at Bus 2, and fine-tuning the output power of Generator 1. It is important to note that these adjustments do not impact the branches, leaving the nodal matrix unchanged. To resolve this updated system, users can simply execute the solve! function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.2)\naddGenerator!(system, analysis; label = \"Generator 3\", bus = \"Bus 2\", active = 0.3)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 2.1)\n\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nIn this scenario, JuliaGrid will recognize instances where the user has not modified branch parameters affecting the nodal matrix. Consequently, JuliaGrid will leverage the previously performed nodal matrix factorization, resulting in a significantly faster solution compared to recomputing the factorization.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Limitations","page":"DC Power Flow","title":"Limitations","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The dcPowerFlow function oversees bus type validations, as detailed in the Bus Type Modification section. Consequently, if a user intends to change the slack bus or leaves an existing slack bus without a generator, proceeding directly to the solve! function is not feasible.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In these instances, JuliaGrid will raise an error:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 1\", status = 0)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Now, the user must execute the dcPowerFlow function instead of attempting to reuse the DCPowerFlow type:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"updateGenerator!(system; label = \"Generator 1\", status = 0)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nAfter creating the PowerSystem and DCPowerFlow types, users can add or modify buses, branches, and generators before directly using the solve! function. JuliaGrid automatically executes the necessary functions when adjustments lead to a valid solution. However, if modifications are incompatible, like changing the slack bus, JuliaGrid raises an error to prevent misleading outcomes, ensuring accuracy.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerAnalysisManual","page":"DC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution, we can calculate powers related to buses, branches, and generators using the power! function. For example, let us consider the power system for which we obtained the DC power flow solution:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Now we can calculate the active powers using the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Next, let us convert the base power unit to megavolt-amperes (MVA):","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@base(system, MVA, V)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, here are the calculated active power values in megawatts (MW) corresponding to buses and branches:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, system.base.power.value * analysis.power.injection.active)\nprint(system.branch.label, system.base.power.value * analysis.power.from.active)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nTo better understand the powers associated with buses, branches, and generators that are calculated by the power! function, we suggest referring to the tutorials on DC Power Flow Analysis.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Print-Results-in-the-REPL-2","page":"DC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, users have the option to print the results in the REPL using any units that have been configured:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@power(MW, pu, pu)\nprintBranchData(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Injection","page":"DC Power Flow","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Injection-from-Generators","page":"DC Power Flow","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Flow","page":"DC Power Flow","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = fromPower(system, analysis; label = \"Branch 2\")\nactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Generator-Active-Power-Output","page":"DC Power Flow","title":"Generator Active Power Output","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, we can compute the active power output of a particular generator using the function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = generatorPower(system, analysis; label = \"Generator 1\")\n@voltage(pu, pu, V) # hide\n@power(pu, pu, pu) # hide","category":"page"},{"location":"tutorials/measurementModel/#MeasurementModelTutorials","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us begin by examining a power system. To do that, we will construct one as shown below:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = 1)\naddBus!(system; label = 2)\naddBus!(system; label = 3)\n\n@branch(reactance = 0.03)\naddBranch!(system; label = 1, from = 1, to = 2)\naddBranch!(system; label = 2, from = 1, to = 3)\naddBranch!(system; label = 3, from = 2, to = 3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Our goal is to monitor the power system, and this process involves collecting measurement data for various electrical quantities distributed throughout the power system.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Power-System-Monitoring","page":"Measurement Model","title":"Power System Monitoring","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Measurement data is obtained through two main technologies: SCADA (Supervisory Control and Data Acquisition) and WAMS (Wide Area Measurement System). These technologies enable the collection of a wide range of measurements distributed throughout the power system. This extensive dataset allows us to employ state estimation algorithms to obtain the present state of the power system, in contrast to power flow algorithms, which are typically used for offline analyses. To commence, we will represent the entire set of measurement devices as mathcalM.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"SCADA provides legacy measurements with low sampling rates, making them unsuitable for capturing real-time system dynamics. It provides a snapshot of the power system's state, with delays measured in seconds and minutes. These legacy measurement devices, subsets of the set mathcalM, include:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"a set of voltmeters mathcalV for measuring bus voltage magnitudes,\na set of ammeters mathcalI for measuring branch current magnitudes,\na set of wattmeters mathcalP for active power injection and flow measurements,\na set of varmeters mathcalQ for reactive power injection and flow measurements.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In contrast, WAMS technology utilizes PMUs (Phasor Measurement Units) to provide data with high sampling rates, typically ranging between 10 and 20 ms, facilitating real-time monitoring of the system. Therefore, PMUs expand the set mathcalM as follows:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"a set of PMUs barmathcalP for bus voltage and branch current phasor measurements.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i, where a_i represents the element associated measurement i in mathcalM.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Measurement-Model","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The measurement model, as defined by the set mathcalM, can be expressed as a system of equations [12]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"where mathbf x=x_1dotsx_n^T is the vector of state variables, mathbfh(mathbfx)= h_1(mathbfx), dots, h_k(mathbfx)^T is the vector of measurement functions, mathbfz = z_1dotsz_k^mathrmT is the vector of measurement values, and mathbfu = u_1dotsu_k^mathrmT is the vector of measurement errors. In the context of transmission grids, this model is often an overdetermined system of equations (ks) [13, Sec. 2.1].","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"These errors are assumed to follow a Gaussian distribution with a zero-mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T. These covariances exist only if PMUs are observed in rectangular coordinates and correlation is required.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Gaussian-Probability-Density-Function","page":"Measurement Model","title":"Gaussian Probability Density Function","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Each legacy measurement and each magnitude or angle measurement from PMUs is associated with a measured value z_i, a measurement error u_i, and a measurement function h_i(mathbfx). Assuming that measurement errors u_i follow a zero mean Gaussian distribution, the probability density function associated with the i-th measurement is proportional to:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" mathcalN(z_imathbfxv_i) propto expBiggcfracz_i-h_i(mathbfx)^22v_iBigg","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"where v_i is the measurement variance defined by the measurement error u_i, and the measurement function h_i(mathbfx) connects the vector of state variables mathbfx to the value of the i-th measurement.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Artificial-Generation-of-Measurement-Values","page":"Measurement Model","title":"Artificial Generation of Measurement Values","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When defining the system of equations, it is essential to have measurement values represented by mathbfz. In JuliaGrid, users have the option to either directly specify measurement values or artificially generate the vector mathbfz. The artificial generation process involves setting the keyword noise = true, which introduces white Gaussian noise with variances v_1 dots v_k added to the provided values e_1 dots e_k, typically representing the exact values of the respective electrical quantities:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" epsilon_i sim mathcalN(0v_i) 5pt\n z_i = e_i + epsilon_i","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Voltmeters","page":"Measurement Model","title":"Voltmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A voltmeter V_i in mathcalV measures the bus voltage magnitude at bus i in mathcalN. Let us introduce two voltmeters that measure voltage magnitudes at the first and third bus. For the first voltmeter, we directly pass the measurement value, while for the second voltmeter, we generate the measurement value artificially:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!(system, device; label = \"V₁\", bus = 1, magnitude = 1.1, variance = 1e-3)\naddVoltmeter!(system, device; label = \"V₃\", bus = 3, magnitude = 1.0, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of voltmeters mathcalV subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒱 = collect(keys(device.voltmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of voltmeters defines vectors of measurement values denoted as mathbfz_mathcalV = z_i and variances denoted as mathbfv_mathcalV = v_i, where i in mathcalV, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ᵥ = device.voltmeter.magnitude.mean\n𝐯ᵥ = device.voltmeter.magnitude.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Ammeters","page":"Measurement Model","title":"Ammeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"An ammeter I_ij in mathcalI measures the magnitude of branch current at the from-bus end of the branch (ij) in mathcalE. Let us add this type of ammeter at the first branch between buses 1 and 2:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(system, device; label = \"I₁₂\", from = 1, magnitude = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Additionally, an ammeter can measure the branch current magnitude at the to-bus end of the branch (ij) in mathcalE, denoted as I_ji in mathcalI. For example, we can include this type of ammeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(system, device; label = \"I₂₁\", to = 1, magnitude = 0.2, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of ammeters mathcalI subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"ℐ = collect(keys(device.ammeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of ammeters defines vectors of measurement values denoted as mathbfz_mathcalI = z_i and variances denoted as mathbfv_mathcalI = v_i, where i in mathcalI, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₒ = device.ammeter.magnitude.mean\n𝐯ₒ = device.ammeter.magnitude.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Wattmeters","page":"Measurement Model","title":"Wattmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A wattmeter P_i in mathcalP measures the active power injection at bus i in mathcalN. Hence, let us add it to the second bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₂\", bus = 2, active = 0.1, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a wattmeter denoted as P_ij in mathcalP measures the active power flow at the from-bus end of the branch (ij) in mathcalE. Let us add this type of wattmeter at the second branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₁₃\", from = 2, active = 0.2, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a wattmeter can also measure the active power flow at the to-bus end of the branch (ij) in mathcalE, denoted as P_ji in mathcalP. For example, we can include this type of wattmeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₃₁\", to = 2, active = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of wattmeters mathcalP subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒫 = collect(keys(device.wattmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of wattmeters defines vectors of measurement values denoted as mathbfz_mathcalP = z_i and variances denoted as mathbfv_mathcalP = v_i, where i in mathcalP, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₚ = device.wattmeter.active.mean\n𝐯ₚ = device.wattmeter.active.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Varmeters","page":"Measurement Model","title":"Varmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A varmeter Q_i in mathcalQ measures the reactive power injection at bus i in mathcalN. Hence, let us add it to the first bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₁\", bus = 1, reactive = 0.01, variance = 1e-2)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a varmeter denoted as Q_ij in mathcalQ measures the reactive power flow at the from-bus end of the branch (ij) in mathcalE. Let us add this type of varmeter at the first branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₁₂\", from = 1, reactive = 0.02, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a varmeter can also measure the reactive power flow at the to-bus end of the branch (ij) in mathcalE, denoted as Q_ji in mathcalQ. For example, we can include this type of varmeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₂₁\", to = 1, reactive = 0.03, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of varmeters mathcalQ subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒬 = collect(keys(device.varmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of varmeters defines vectors of measurement values denoted as mathbfz_mathcalQ = z_i and variances denoted as mathbfv_mathcalQ = v_i, where i in mathcalQ, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₒ = device.varmeter.reactive.mean\n𝐯ₒ = device.varmeter.reactive.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#PMUs","page":"Measurement Model","title":"PMUs","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"PMUs measure voltage and current phasors in the polar coordinate system, thus each PMU output is represented by magnitude and angle along with corresponding variances [14, Sec. 5.6]. When installed on buses, they measure bus voltage phasors, while on branches, they measure current phasors.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A PMU (V_i theta_i) in barmathcalP measures the voltage phasor at bus i in mathcalN. Let us integrate this type of PMU at the first bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1, angle = 0, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a PMU (I_ij psi_ij) in barmathcalP measures the branch current magnitude at the from-bus end of the branch (ij) in mathcalE. Let us add this type of PMU at the first branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"I₁₂, ψ₁₂\", from = 1, magnitude = 0.2, angle = -0.1)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a PMU can measure the branch current magnitude at the to-bus end of the branch (ij) in mathcalE, denoted as (I_ji psi_ji) in barmathcalP. For example, let us include this type of PMU at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"I₂₁, ψ₂₁\", to = 1, magnitude = 0.3, angle = -0.2)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of PMUs barmathcalP subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒫̄ = collect(keys(device.pmu.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of PMUs establishes vectors representing measurement magnitudes and angles mathbfz_barmathcalP = z_i z_j, along with their corresponding variances mathbfv_barmathcalP = v_i v_j, where (i j) in barmathcalP. These values can be accessed as:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"pmu = device.pmu;\n\n𝐳ₚ = collect(Iterators.flatten(zip(pmu.magnitude.mean, pmu.angle.mean)))\n𝐯ₚ = collect(Iterators.flatten(zip(pmu.magnitude.variance, pmu.angle.variance)))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nPMUs can be handled in state estimation algorithms according to our definition in polar coordinate systems. However, they can also be processed in rectangular coordinates, where we observe the real and imaginary parts of the phasor measurements rather than magnitude and angle. Further details can be found in tutorials that describe specific state estimation analyses.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#State-Estimation","page":"Measurement Model","title":"State Estimation","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"After establishing the measurement model, which includes specifying measurement values, variances, the locations of measurement devices, and known power system network parameters, the subsequent step involves the process of state estimation. State estimation is a component of energy management systems and typically encompasses network topology processing, observability analysis, state estimation algorithms, and bad data analysis.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The primary goal of state estimation algorithms is to determine state variables, often associated with bus voltages. Therefore, by representing the vector of state variables as mathbfx and the vector of noisy measurement values as mathbfz, we can effectively describe the state estimation problem using the following conditional probability equation:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" \t\tp(mathbfxmathbfz)= cfracp(mathbfzmathbfx)p(mathbfx)p(mathbfz)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"If we assume that the prior probability distribution p(mathbfx) is uniform and that p(mathbfz) does not depend on mathbfx, the maximum a posteriori solution simplifies to the maximum likelihood solution, as shown below [15]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbfx = mathrmargmax_mathbfxp(mathbfxmathbfz) =\n\tmathrmargmax_mathbfxp(mathbfzmathbfx) = mathrmargmax_mathbfxmathcalL(mathbfzmathbfx)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"We can find this solution by maximizing the likelihood function mathcalL(mathbfzmathbfx), which is defined based on the likelihoods of k independent measurements:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbf x = mathrmarg max_mathbfxmathcalL(mathbfzmathbfx)=\n\tmathrmarg max_mathbfx prod_i=1^k mathcalN(z_imathbfxv_i)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"It can be demonstrated that the solution to the maximum a posteriori problem can be obtained by solving the following optimization problem, commonly referred to as the weighted least-squares problem [9, Sec. 9.3]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbf x = mathrmargmin_mathbfx sum_i=1^kcfracz_i-h_i(mathbf x)^2v_i","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The state estimate, denoted as hatmathbf x, resulting from the solution to the above optimization problem, is known as the weighted least-squares estimator. Both the maximum likelihood and weighted least-squares estimators are equivalent to the maximum a posteriori solution [15, Sec. 8.6].","category":"page"},{"location":"manual/measurementModel/#MeasurementModelManual","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The JuliaGrid supports the type Measurement to preserve measurement data, with the following fields: voltmeter, ammeter, wattmeter, varmeter, and pmu. These fields contain information pertaining to measurements such as bus voltage magnitude, branch current magnitude, active power flow and injection, reactive power flow and injection measurements, and measurements of bus voltage and branch current phasors.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The type Measurement can be created using a function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid supports two modes for populating the Measurement type: using built-in functions or using HDF5 files.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To work with HDF5 files, JuliaGrid provides the function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"saveMeasurement.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once the Measurement type has been established, we can incorporate voltmeters, ammeters, wattmeters, varmeters, and phasor measurement units (PMUs) using the following functions:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!,\naddAmmeter!,\naddWattmeter!,\naddVarmeter!,\naddPmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Also, JuliaGrid provides macros @voltmeter, @ambmeter, @wattmeter, @varmeter, and @pmu to define templates that aid in creating measurement devices. These templates help avoid entering the same parameters repeatedly.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nIt is important to note that measurement devices associated with branches can only be incorporated if the branch is in-service. This reflects JuliaGrid's approach to mimic a network topology processor, where logical data analysis configures the energized components of the power system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, it is feasible to modify the parameters of measurement devices. When these functions are executed, all relevant fields within the Measurement type will be automatically updated. These functions include:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVoltmeter!,\nupdateAmmeter!,\nupdateWattmeter!,\nupdateVarmeter!,\nupdatePmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nThe functions for updating measurement devices serve a dual purpose. While their primary function is to modify the Measurement type, they are also designed to accept various analysis models like AC or DC state estimation models. When feasible, these functions not only modify the Measurement type but also adapt the analysis model, often resulting in improved computational efficiency. Detailed instructions on utilizing this feature can be found in dedicated manuals for specific analyses.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Finally, the user has the capability to randomly alter the measurement set by activating or deactivating devices through the following function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, we provide users with the ability to modify each specific measurement set by utilizing the functions:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusVoltmeter!,\nstatusAmmeter!,\nstatusWattmeter!,\nstatusVarmeter!,\nstatusPmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#BuildMeasurementModelManual","page":"Measurement Model","title":"Build Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The measurement function generates the Measurement type and requires a string-formatted path to HDF5 files as input. Alternatively, the Measurement can be created without any initial data by initializing it as empty, allowing the user to construct the measurements from scratch.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#HDF5-File","page":"Measurement Model","title":"HDF5 File","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In order to use the HDF5 file as input to create the Measurement type, it is necessary to have saved the data using the saveMeasurement function beforehand. Let us say we saved the measurements as measurements14.h5 in the directory C:\\hdf5. Then, the following code can be used to construct the Measurement type:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device = measurement(\"C:/hdf5/measurements14.h5\")","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Model-from-Scratch","page":"Measurement Model","title":"Model from Scratch","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To start building a model from the ground up, the initial step involves constructing a power system, which facilitates the addition of measurement devices to buses or branches. As an illustration:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.2, variance = 1e-4, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, we have created the voltmeter responsible for measuring the bus voltage magnitude at Bus 1, with associated mean and variance values expressed in per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, we have established the wattmeter to measure the active power flow at the from-bus end of Branch 1, with corresponding mean and variance values also expressed in per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nThe measurement values (i.e., means) can be generated by adding white Gaussian noise with specified variance values to perturb the original values. This can be achieved by setting noise = true within the functions used for adding devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#SaveMeasurementModelManual","page":"Measurement Model","title":"Save Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once the Measurement type has been created using one of the methods outlined in Build Model, the current data can be stored in the HDF5 file by using saveMeasurement function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"saveMeasurement(device; path = \"C:/hdf5/measurement.h5\")","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"All electrical quantities saved in the HDF5 file are in per-units and radians.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddVoltmeterManual","page":"Measurement Model","title":"Add Voltmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"We have the option to add voltmeters to a loaded measurement type or to one created from scratch. As an example, we can initiate the Measurement type and then incorporate voltmeters by utilizing the addVoltmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 0.9, variance = 1e-4)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have established two voltmeters designed to measure the bus voltage magnitude at Bus 1. In the case of the second voltmeter, the measurement value is generated internally by introducing white Gaussian noise with the variance added to the magnitude value. As a result, we obtain the following data:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addVoltmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and variance keywords are expected to be provided in per-units (pu). However, users have the flexibility to specify these values in volts (V) if they prefer. For instance, consider the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\n@voltage(kV, rad, V)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = sqrt(3) * 135e3)\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 121.5, variance = 0.0135)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 135, variance = 0.135, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have chosen to specify magnitude and variance in kilovolts (kV). It is important to note that even though we have used kilovolts as the input units, these keywords will still be stored in the per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWhen users choose to input data in volts, measurement values and variances are related to line-to-neutral voltages, while the base values are defined for line-to-line voltages. Therefore, a conversion using sqrt3 is necessary. For more information, refer to the Per-Unit System section.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the voltmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printVoltmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddAmmeterManual","page":"Measurement Model","title":"Add Ammeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users can introduce ammeters into either an existing measurement type or one that they create from the ground up by making use of the addAmmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 0.8, variance = 1e-3)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 0.9, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario, we have established one ammeter to measure the branch current magnitude at the from-bus end of Branch 1, as indicated by the use of the from keyword. Similarly, we have added an ammeter to measure the branch current magnitude at the to-bus end of the branch by utilizing the to keyword.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first ammeter, we assume that the measurement value is already known, defined by the magnitude. In contrast, for the second ammeter, the measurement value is generated by adding white Gaussian noise with the variance to the magnitude value. These actions result in the following outcomes:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.ammeter.magnitude.mean device.ammeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addAmmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-2","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and variance keywords are expected to be provided in per-unit (pu). However, users have the flexibility to express these values in amperes (A) if they prefer. Take a look at the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@current(A, rad)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 135e3)\naddBus!(system; label = \"Bus 2\", base = 135e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 342.13, variance = 0.428)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 385, variance = 42.8, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have opted to specify the magnitude and variance in amperes (A). It is worth noting that, despite using amperes as the input units, these keywords will still be stored in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.ammeter.magnitude.mean device.ammeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-2","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the ammeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printAmmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddWattmeterManual","page":"Measurement Model","title":"Add Wattmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users can include wattmeters in either an existing measurement type or one that they create from scratch by utilizing the addWattmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.3, variance = 1e-2)\naddWattmeter!(system, device; to = \"Branch 1\", active = 0.1, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario, one wattmeter has been added to measure the active power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two wattmeters have been introduced to measure the active power flow on both sides of Branch 1 using the from and to keywords.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first and second wattmeters, we assume that the measurement values are already known, defined by the active. In contrast, for the third wattmeter, the measurement value is generated by adding white Gaussian noise with the variance to the active value. As a result, the measurement data is as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addWattmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-3","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the active and variance keywords are expected to be provided in per-unit (pu) values. However, users have the option to express these values in watts (W) if they prefer, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@power(MW, pu, pu)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 60, variance = 1e-1)\naddWattmeter!(system, device; from = \"Branch 1\", active = 30, variance = 1)\naddWattmeter!(system, device; to = \"Branch 1\", active = 10, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have chosen to specify the active and variance in megawatts (MW), but even though we have used megawatts as the input units, these keywords will still be stored in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-3","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the wattmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printWattmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddVarmeterManual","page":"Measurement Model","title":"Add Varmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To include varmeters, the same approach as described in the Add Wattmeter section can be applied, but here, we make use of the addVarmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVarmeter!(system, device; bus = \"Bus 1\", reactive = 0.2, variance = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.1, variance = 1e-2)\naddVarmeter!(system, device; to = \"Branch 1\", reactive = 0.05, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, one varmeter has been added to measure the reactive power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two varmeters have been introduced to measure the reactive power flow on both sides of Branch 1 using the from and to keywords. As a result, the following outcomes are observed:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.varmeter.reactive.mean device.varmeter.reactive.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addVarmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-4","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Just as we explained for the previous device, users have the flexibility to select units different from per-units. In this case, they can opt for megavolt-ampere reactive (MVAr), as illustrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@power(pu, MVAr, pu)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVarmeter!(system, device; bus = \"Bus 1\", reactive = 20, variance = 1e-1)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 10, variance = 1)\naddVarmeter!(system, device; to = \"Branch 1\", reactive = 5, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid will still store the values in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.varmeter.reactive.mean device.varmeter.reactive.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-4","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the varmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printVarmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddPMUManual","page":"Measurement Model","title":"Add PMU","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the capability to incorporate PMUs into either an existing measurement type or create one from scratch by utilizing the addPmu! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.1, angle = 0.1, varianceMagnitude = 0.1)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 1.0, angle = -0.2, noise = true)\naddPmu!(system, device; to = \"Branch 1\", magnitude = 0.9, angle = 0.0, varianceAngle = 0.001)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWhile the typical understanding of a PMU encompasses a device that measures the bus voltage phasor and all branch current phasors incident to the bus, we have chosen to deconstruct this concept to offer users increased flexibility. As a result, our approach yields PMUs that measure individual phasors, each described with magnitude and angle, along with corresponding variances, all presented in the polar coordinate system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, one PMU has been added to measure the bus voltage phasor at Bus 1, as indicated by the use of the bus keyword. Additionally, two PMUs have been introduced to measure the branch current phasors on both sides of Branch 1 using the from and to keywords.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first and third PMUs, we assume that the measurement values are already known, defined by the magnitude and angle keywords. However, for the second PMU, we generate the measurement value by adding white Gaussian noise with varianceMagnitude and varianceAngle to the magnitude and angle values, respectively. It is important to note that when we omit specifying variance values, we rely on their default settings, both of which are equal to 1e-5. As a result, we observe the following outcomes:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.pmu.magnitude.mean device.pmu.magnitude.variance]\n[device.pmu.angle.mean device.pmu.angle.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addPmu! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Coordinate-Systems-and-Correlated-Measurement-Errors","page":"Measurement Model","title":"Coordinate Systems and Correlated Measurement Errors","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When users add PMUs, the incorporation of these measurements into the state estimation model is always in the rectangular coordinate system. In this scenario, the real and imaginary components of the phasor measurements become correlated, although typically these correlations are disregarded [1]. However, if users want to consider these error correlations, the keyword correlated = true is provided for support.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Further, in the AC state estimation model, users have the flexibility to integrate PMU outputs in the polar coordinate system by specifying polar = true.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For example, let us add PMUs:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.9, angle = 0, correlated = true)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.9, angle = 0, polar = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In the case of linear state estimation using PMUs only, both PMUs will be integrated into the rectangular coordinate system because the polar keyword is only related to AC state estimation. The treatment of the first PMU assumes error correlation between the real and imaginary parts. Conversely, the treatment of the second PMU assumes no correlation, as it defaults to correlated = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, in AC state estimation, the first PMU measurement will be integrated into the rectangular coordinate system where correlation between the real and imaginary parts exists. The second PMU will be integrated in the polar coordinate system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nIt is noteworthy that expressing current phasor measurements in polar coordinates can lead to ill-conditioned problems due to small current magnitudes, whereas using rectangular representation can resolve this issue.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-5","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and varianceMagnitude keywords are expected to be provided in per-unit (pu), while the angle and varianceAngle keywords are expected to be provided in radians (rad). However, users have the flexibility to express these values in different units, such as volts (V) and degrees (deg) if the PMU is set to a bus, or amperes (A) and degrees (deg) if the PMU is set to a branch. This flexibility is demonstrated in the following:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@voltage(kV, deg, V)\n@current(A, deg)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 135e3)\naddBus!(system; label = \"Bus 2\", base = 135e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 85.74, angle = 5.73, varianceAngle = 0.06)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 167.35, angle = -11.46, noise = true)\naddPmu!(system, device; to = \"Branch 1\", magnitude = 150.61, angle = 0.0)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have opted to specify kilovolts (kV) and degrees (deg) for the PMU located at Bus 1, and amperes (A) and degrees (deg) for the PMUs located at Branch 1. It is important to note that regardless of the units used, the values will still be stored in per-units and radians:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.pmu.magnitude.mean device.pmu.magnitude.variance]\n[device.pmu.angle.mean device.pmu.angle.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-5","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the PMU data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printPmuData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddTemplatesMeasurementManual","page":"Measurement Model","title":"Add Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The functions addVoltmeter!, addAmmeter!, addWattmeter!, addVarmeter!, and addPmu! are employed to introduce measurement devices. In cases where specific keywords are not explicitly defined, default values are automatically assigned to certain parameters.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Default-Keyword-Values","page":"Measurement Model","title":"Default Keyword Values","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When utilizing the addVoltmeter! function, the default variance is set to variance = 1e-2 per-unit, and the voltmeter's operational status is automatically assumed to be in-service, as indicated by the setting of status = 1.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, for the addAmmeter! function, the default variances are established at variance = 1e-2 per-unit, and the operational statuses are configured to status = 1. This means that if a user places an ammeter at either the from-bus or to-bus end of a branch, the default settings are identical. However, as we will explain in the following subsection, users have the flexibility to fine-tune these default values, differentiating between the two locations.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In alignment with ammeters, the addWattmeter! and addVarmeter! functions feature default variances set at variance = 1e-2 per-unit, and statuses are automatically assigned as status = 1, regardless of whether the wattmeter or varmeter is placed at the bus, the from-bus end, or the to-bus end. Users have the ability to customize these default values, making distinctions between the three positions of the measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the addPmu! function, variances for both magnitude and angle measurements are standardized to varianceMagnitude = 1e-5 and varianceAngle = 1e-5 in per-units. Likewise, operational statuses are uniformly set to statusMagnitude = 1 and statusAngle = 1, regardless of whether the PMU is positioned on the bus, the from-bus end, or the to-bus end. Once more, users retain the option to tailor these default values to their specific needs, allowing for distinctions between these three locations of the measurement devices. Additionally, the coordinate system utilized for AC state estimation is consistently configured with polar = false, while correlation in the rectangular system is disabled with correlated = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Across all measurement devices, the method for generating measurement means is established as noise = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#ChangeKeywordsMeasurementManual","page":"Measurement Model","title":"Change Default Keyword Values","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In JuliaGrid, users have the flexibility to customize default values and assign personalized settings using the @voltmeter, @ammeter, @wattmeter, @varmeter, and @pmu macros. These macros create voltmeter, ammeter, wattmeter, varmeter, and pmu templates that are employed each time functions for adding measurement devices are called. Here is an example of creating these templates with tailored default values:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n@voltmeter(variance = 1e-4, noise = true)\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.0)\n\n@ammeter(varianceFrom = 1e-3, varianceTo = 1e-4, statusTo = 0)\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 0.9)\n\n@wattmeter(varianceBus = 1e-3, statusFrom = 0, noise = true)\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 1\", active = 0.6)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 0.3)\naddWattmeter!(system, device; label = \"Wattmeter 3\", to = \"Branch 1\", active = 0.1)\n\n@varmeter(varianceFrom = 1e-3, varianceTo = 1e-3, statusBus = 0)\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 1\", reactive = 0.2)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 0.1)\naddVarmeter!(system, device; label = \"Varmeter 3\", to = \"Branch 1\", reactive = 0.05)\n\n@pmu(varianceMagnitudeBus = 1e-4, statusAngleBus = 0, varianceAngleFrom = 1e-3)\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 1.0, angle = -0.2)\naddPmu!(system, device; label = \"PMU 3\", to = \"Branch 1\", magnitude = 0.9, angle = 0.0)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For instance, when adding a wattmeter to the bus, the varianceBus = 1e-3 will be applied, or if it is added to the from-bus end of the branch, these wattmeters will be set as out-of-service according to statusFrom = 0.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, when adding a PMU to the bus, the variance of the bus voltage magnitude will be defined in accordance with varianceMagnitudeBus = 1e-4, while the bus voltage angle measurements will be configured as out-of-service based on the statusAngleBus = 0.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"It is important to note that changing input units will also impact the templates accordingly.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Multiple-Templates","page":"Measurement Model","title":"Multiple Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In the case of calling the macros multiple times, the provided keywords and values will be combined into a single template for the corresponding measurement device.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Reset-Templates","page":"Measurement Model","title":"Reset Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To reset the measurement device templates to their default settings, users can utilize the following macros:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"@default(voltmeter)\n@default(ammeter)\n@default(wattmeter)\n@default(varmeter)\n@default(pmu)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Additionally, users can reset all templates using the macro:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"@default(template)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#LabelsMeasurementManual","page":"Measurement Model","title":"Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid necessitates a unique label for each voltmeter, ammeter, wattmeter, varmeter, or pmu. These labels are stored in order dictionaries, functioning as pairs of strings and integers. The string signifies the distinct label for the particular device, while the integer tracks the internal numbering of measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In all the previous examples, with the exception of the last one, we relied on automatic labeling by omitting the label keyword. This allowed JuliaGrid to independently assign unique labels to measurement devices. In such cases, JuliaGrid utilizes a sequential set of increasing integers for labeling the devices. The last example demonstrates the user labeling approach.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nString labels improve readability, but in larger models, the overhead from using strings can become substantial. To reduce memory usage, users can configure ordered dictionaries to accept and store integers as labels:@labels(Integers)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Integer-Based-Labeling","page":"Measurement Model","title":"Integer-Based Labeling","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us take a look at the following illustration:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integers)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = 1)\naddBus!(system; label = 2)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.12)\n\naddVoltmeter!(system, device; label = 1, bus = 1, magnitude = 1.0)\n\naddAmmeter!(system, device; label = 1, from = 1, magnitude = 1.1)\naddAmmeter!(system, device; label = 2, to = 1, magnitude = 0.9)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we use the macro @labels to specify that labels will be stored as integers. It is essential to run this macro; otherwise, even if integers are used in subsequent functions, they will be stored as strings.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Automated-Labeling-Using-Templates","page":"Measurement Model","title":"Automated Labeling Using Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can create labels using templates and include the symbol ? to insert an incremental set of integers at any position. In addition, users have the option to use the symbol ! to insert the location of the measurement device into the label. For example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n@voltmeter(label = \"Voltmeter ?\")\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\naddVoltmeter!(system, device; bus = \"Bus 2\", magnitude = 0.9)\n\n@ammeter(label = \"!\")\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 0.9)\n\n@wattmeter(label = \"Wattmeter ?: !\")\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.3)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To illustrate, the voltmeter labels are defined with incremental integers as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.voltmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, for ammeter labels, location information is employed:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.ammeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Lastly, for wattmeters, a combination of both approaches is used:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.wattmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Retrieving-Labels","page":"Measurement Model","title":"Retrieving Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us explore how to retrieve stored labels. Consider the following model:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 1\", reactance = 0.14)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", bus = \"Bus 2\", active = 0.6)\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 1\", active = 0.2)\naddWattmeter!(system, device; label = \"Wattmeter 4\", from = \"Branch 1\", active = 0.3)\naddWattmeter!(system, device; label = \"Wattmeter 3\", to = \"Branch 1\", active = 0.1)\naddWattmeter!(system, device; label = \"Wattmeter 5\", from = \"Branch 2\", active = 0.1)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To access the wattmeter labels, we can use the variable:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.wattmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"If we need to obtain only labels, we can use the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(device.wattmeter.label))","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To isolate the wattmeters positioned either at the buses or at the ends of branches (from-bus or to-bus), users can achieve this using the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label[device.wattmeter.layout.bus]\nlabel[device.wattmeter.layout.from]\nlabel[device.wattmeter.layout.to]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, when using the addWattmeter! function, the labels for the keywords bus, from, and to are stored internally as numerical values. To retrieve bus labels, we can follow this procedure:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(system.bus.label));\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.bus]]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, to obtain labels for branches, we can use the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(system.branch.label));\n\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.from]]\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.to]]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This procedure is applicable to all measurement devices, including voltmeters, ammeters, varmeters, and PMUs.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nJuliaGrid offers the capability to print labels alongside various types of data. For instance, users can use the following code to print labels in combination with specific data:print(device.wattmeter.label, device.wattmeter.active.mean)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Loading-and-Saving-Labels","page":"Measurement Model","title":"Loading and Saving Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When saving the measurements to an HDF5 file, the label type (strings or integers) will match the type chosen during system setup. Likewise, when loading data from an HDF5 file, the label type will be preserved as saved, regardless of what is set by the @labels macro.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddDeviceGroupsManual","page":"Measurement Model","title":"Add Multiple Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to add measurement devices with data generated from one of the AC analyses, specifically, using results obtained from either AC power flow or AC optimal power flow. To do this, users simply need to provide the AC type as an argument to one of the functions responsible for adding measurement devices:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.03, susceptance = 0.02)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.2)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\ncurrent!(system, analysis)\n\n@voltmeter(label = \"!\", noise = true)\naddVoltmeter!(system, device, analysis; variance = 1e-3)\n\n@ammeter(label = \"!\")\naddAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0, noise = true)\n\n@wattmeter(label = \"!\")\naddWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)\n\n@varmeter(label = \"!\")\naddVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)\n\n@pmu(label = \"!\", polar = true)\naddPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we incorporate voltmeters to all buses and ammeters to all branches on both ends of each branch. We set noise = true once in the template and once directly in the function, which means that measurement values are generated by adding white Gaussian noise with specified variances to perturb the values obtained from the AC power flow analysis.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For wattmeters, varmeters, and PMUs added to all buses and branches, we rely on the default setting of noise = false to obtain measurement values that match precisely with those obtained from the AC power flow analysis. Additionally, when including PMUs in the AC state estimation model, we opt for the polar coordinate system by setting polar = true.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nIt is important to note that JuliaGrid follows a specific order: it first adds bus measurements, then branch measurements. For branches, it adds measurement located at the from-bus end, and immediately after, measurement at the to-bus end. This process is repeated for all in-service branches.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to employ an alternative method for adding groups of measurements, utilizing functions that add measurements individually. This approach may offer a more straightforward process. For example, to add wattmeters similarly to the procedure outlined above, we can employ the following:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Pᵢ = analysis.power.injection.active\nfor (label, idx) in system.bus.label\n addWattmeter!(system, device; bus = label, active = Pᵢ[idx], variance = 1e-3)\nend\n\nPᵢⱼ = analysis.power.from.active\nPⱼᵢ = analysis.power.to.active\nfor (label, idx) in system.branch.label\n addWattmeter!(system, device; from = label, active = Pᵢⱼ[idx], status = 0)\n addWattmeter!(system, device; to = label, active = Pⱼᵢ[idx])\nend\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateMeasurementDevicesManual","page":"Measurement Model","title":"Update Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"After the addition of measurement devices to the Measurement type, users possess the flexibility to modify all parameters as defined in the function that added these measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateVoltmeterManual","page":"Measurement Model","title":"Update Voltmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the flexibility to modify all parameters as defined within the addVoltmeter! function. For illustration, let us continue with the example from the Add Device Groups section:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVoltmeter!(system, device; label = \"Bus 2\", magnitude = 0.9, noise = false)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we update the measurement value of the voltmeter located at Bus 2, and this measurement is now generated without the inclusion of white Gaussian noise.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateAmmeterManual","page":"Measurement Model","title":"Update Ammeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, users have the flexibility to modify all parameters defined within the addAmmeter! function. Using the same example from the Add Device Groups section, for example, we have:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateAmmeter!(system, device; label = \"From Branch 2\", magnitude = 1.2, variance = 1e-4)\nupdateAmmeter!(system, device; label = \"To Branch 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we make adjustments to the measurement and variance values of the ammeter located at Branch 2, specifically at the from-bus end. Next, we deactivate the ammeter at the same branch on the to-bus end.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateWattmeterManual","page":"Measurement Model","title":"Update Wattmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Following the same logic, users can modify all parameters defined within the addWattmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateWattmeter!(system, device; label = \"Bus 1\", active = 1.2, variance = 1e-4)\nupdateWattmeter!(system, device; label = \"To Branch 1\", variance = 1e-6)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this case, we modify the measurement and variance values for the wattmeter located at Bus 1. The wattmeter at Branch 1 on the to-bus end retains its measurement value, while only the measurement variance is adjusted.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateVarmeterManual","page":"Measurement Model","title":"Update Varmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Following the same logic, users can modify all parameters defined within the addVarmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVarmeter!(system, device; label = \"Bus 1\", reactive = 1.2)\nupdateVarmeter!(system, device; label = \"Bus 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this instance, we make adjustments to the measurement value of the varmeter located at Bus 1, while utilizing a previously defined variance. Furthermore, we deactivate the varmeter at Bus 2 and designate it as out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdatePMUrManual","page":"Measurement Model","title":"Update PMU","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Finally, users can modify all PMU parameters defined within the addPmu! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updatePmu!(system, device; label = \"Bus 1\", magnitude = 1.05, noise = true)\nupdatePmu!(system, device; label = \"From Branch 1\", varianceAngle = 1e-6, polar = false)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we adjust the magnitude measurement value of the PMU located at Bus 1. Now, this measurement is generated by adding white Gaussian noise with specified variance value to perturb the magnitude value, while keeping the bus angle voltage value unchanged. For the PMU placed at Branch 1 on the from-bus end, we retain the existing measurement values and only adjust the variance of the angle measurement. Additionally, we choose to include this measurement in the rectangular coordinate system for the AC state estimation.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#MeasurementSetManual","page":"Measurement Model","title":"Measurement Set","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once measurement devices are integrated into the Measurement type, we empower users to create measurement sets in a randomized manner. To be more precise, users can manipulate the status of devices, activating or deactivating them according to specific settings. To illustrate this feature, let us first create a measurement set using the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.03, susceptance = 0.02)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.2)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\ncurrent!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddAmmeter!(system, device, analysis)\naddPmu!(system, device, analysis)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Activating-Devices","page":"Measurement Model","title":"Activating Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"As a starting point, we create the measurement set where all devices are set to in-service mode based on default settings. In this instance, we generate the measurement set comprising 3 voltmeters, 6 ammeters, and 9 PMUs.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Subsequently, we offer users the ability to manipulate the status of in-service devices using the status! function. For example, within this set, if we wish to have only 12 out of the total 18 devices in-service while the rest are out-of-service, we can accomplish this as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; inservice = 12)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Upon executing this function, 12 devices will be randomly selected to be in-service, while the remaining 6 will be set to out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can fine-tune the manipulation of specific measurements. Let us say we want to activate only 2 ammeters while deactivating the remaining ammeters:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusAmmeter!(system, device; inservice = 2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This action will result in 2 ammeters being in-service and 4 being out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users also have the option to further refine these actions by specifying devices at particular locations within the power system. For instance, we can enable 3 PMUs at buses to measure bus voltage phasors while deactivating all PMUs at branches that measure current phasors:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusPmu!(system, device; inserviceBus = 3, inserviceFrom = 0, inserviceTo = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The outcome will be that 3 PMUs are set to in-service at buses for voltage phasor measurements, while all PMUs at branches measuring current phasors will be in out-of-service mode.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Deactivating-Devices","page":"Measurement Model","title":"Deactivating Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Likewise, we empower users to specify the number of devices to be set as out-of-service rather than defining the number of in-service devices. For instance, if the intention is to deactivate just 2 devices from the total measurement set, it can be achieved as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; outservice = 2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario 2 devices will be randomly deactivated, while the rest will remain in in-service status. Similar to the previous approach, users can apply this to specific devices or employ fine-tuning as needed.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Activating-Devices-Using-Redundancy","page":"Measurement Model","title":"Activating Devices Using Redundancy","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can take advantage of redundancy, which represents the ratio between measurement devices and state variables. For example, if we wish to have the number of measurement devices be 1.2 times greater than the number of state variables, we can utilize the following command:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; redundancy = 1.2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Considering that the number of state variables is 5 (excluding the voltage angle related to the slack bus), using a redundancy value of 1.2 will result in 6 devices being set to in-service, while the remainder will be deactivated. As before, users can target specific devices or adjust settings as needed.","category":"page"},{"location":"background/bibliography/#Bibliography","page":"Bibliography","title":"Bibliography","text":"","category":"section"},{"location":"background/bibliography/","page":"Bibliography","title":"Bibliography","text":"A. Gomez-Exposito, A. Abur, P. Rousseaux, A. de la Villa Jaen and C. Gomez-Quiles. On the use of PMUs in power system state estimation. In: 17th power system computation conference (2011).\n\n\n\nG. N. Korres. Observability analysis based on Echelon form of a reduced dimensional Jacobian matrix. IEEE Transactions on Power Systems 26, 2572–2573 (2011).\n\n\n\nM. Zhou, V. A. Centeno, J. S. Thorp and A. G. Phadke. An alternative for including phasor measurements in state estimators. IEEE transactions on power systems 21, 1930–1937 (2006).\n\n\n\nG. Korres and N. Manousakis. State estimation and observability analysis for phasor measurement unit measured systems. IET generation, transmission & distribution 6, 902–913 (2012).\n\n\n\nA. Abur and A. G. Exposito. Power system state estimation: theory and implementation (CRC press, 2004).\n\n\n\nG. Andersson. Power system analysis. EEH-Power Systems Laboratory, ETH Zurich, Lecture Notes, 227–0526 (2012).\n\n\n\nJ. J. Grainger and W. D. Stevenson. Power system analysis (McGraw-Hill, 1994).\n\n\n\nR. D. Zimmerman and C. E. Murillo-Sánchez. Matpower 6.0 users manual. Power Systems Engineering Research Center 9 (2016).\n\n\n\nA. J. Wood, B. F. Wollenberg and G. B. Sheblé. Power generation, operation, and control (John Wiley & Sons, 2013).\n\n\n\nR. A. Van Amerongen. A general-purpose version of the fast decoupled load flow. IEEE Transactions on Power Systems 4, 760–770 (1989).\n\n\n\nD. P. Chassin, P. R. Armstrong, D. G. Chavarrı́a-Miranda and R. T. Guttromson. Gauss-Seidel accelerated: implementing flow solvers on field programmable gate arrays. In: 2006 IEEE Power Engineering Society General Meeting (IEEE, 2006); p. 5–pp.\n\n\n\nF. C. Schweppe and D. B. Rom. Power system static-state estimation, Part II: Approximate model. IEEE Transactions on Power Apparatus and Systems, 125–130 (1970).\n\n\n\nA. Monticelli. State estimation in electric power systems: a generalized approach (Springer Science & Business Media, 2012).\n\n\n\nA. G. Phadke and J. S. Thorp. Synchronized phasor measurements and their applications. Vol. 1 no. 2017 (Springer, 2008).\n\n\n\nD. Barber. Bayesian reasoning and machine learning (Cambridge University Press, 2012).\n\n\n\nI. ISO. and B. OIML. Guide to the Expression of Uncertainty in Measurement (Aenor, 1993).\n\n\n\nY. Weng, Q. Li, R. Negi and M. Ilić. Semidefinite programming for power system state estimation. In: 2012 IEEE Power and Energy Society General Meeting (IEEE, 2012); pp. 1–8.\n\n\n\nP. C. Hansen, V. Pereyra and G. Scherer. Least squares data fitting with applications (JHU Press, 2013).\n\n\n\nG. N. Korres. A distributed multiarea state estimation. IEEE Transactions on Power Systems 26, 73–84 (2010).\n\n\n\nM. Cosovic, M. Delalic, D. Raca and D. Vukobratovic. Observability analysis for large-scale power systems using factor graphs. IEEE Transactions on Power Systems 36, 4791–4799 (2021).\n\n\n\nH. Horisberger. Observability analysis for power systems with measurement deficiencies. IFAC Proceedings Volumes 18, 51–58 (1985).\n\n\n\nN. M. Manousakis and G. N. Korres. Observability analysis for power systems including conventional and phasor measurements. IET Conference Proceedings, 158-158(1) (2010).\n\n\n\nB. Gou. Optimal placement of PMUs by integer linear programming. IEEE Transactions on power systems 23, 1525–1526 (2008).\n\n\n\nB. Xu and A. Abur. Observability analysis and measurement placement for systems with PMUs. In: IEEE PES Power Systems Conference and Exposition, 2004. (IEEE, 2004); pp. 943–946.\n\n\n\n","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowManual","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid utilizes the JuMP package to construct optimal power flow models, allowing users to manipulate these models using the standard functions provided by JuMP. As a result, JuliaGrid supports popular solvers mentioned in the JuMP documentation to solve the optimization problem.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To perform the AC optimal power flow, we first need to have the PowerSystem type that has been created with the AC model. After that, create the ACOptimalPowerFlow type to establish the AC optimal power flow framework using the function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"acOptimalPowerFlow.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To solve the AC optimal power flow problem and acquire bus voltage magnitudes and angles, and generator active and reactive power outputs, make use of the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"solve!.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the AC optimal power flow solution, JuliaGrid offers post-processing analysis functions to calculate powers and currents associated with buses and branches:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses, branches, or generators.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowModelManual","page":"AC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To set up the AC optimal power flow, we begin by creating the model. To illustrate this, consider the following:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, Ipopt\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.95, maxMagnitude = 1.05)\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, angle = -0.1)\naddBus!(system; label = \"Bus 2\", reactive = 0.01, magnitude = 1.1)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, reactance = 0.5, type = 2)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", maxFromBus = 0.15)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1, status = 0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.4, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, reactive = 0.1)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [800.0; 200.0; 80.0])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\ncost!(system; label = \"Generator 1\", reactive = 2, polynomial = [2.0])\ncost!(system; label = \"Generator 2\", reactive = 1, piecewise = [2.0 4.0; 6.0 8.0])\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, the acOptimalPowerFlow function is utilized to formulate the AC optimal power flow problem:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimizationVariablesManual","page":"AC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow model, the active and reactive power outputs of the generators are expressed as nonlinear functions of the bus voltage magnitudes and angles. As a result, the variables in this model include the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.all_variables(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is important to note that this is not a comprehensive set of optimization variables. When the cost function is defined as a linear piecewise function comprising multiple segments, as illustrated in the case of the active power output cost for Generator 2, JuliaGrid automatically generates helper optimization variables named actwise and reactwise, and formulates a set of linear constraints to effectively address these cost functions. For the sake of simplicity, we initially assume that Generator 2 is out-of-service. Consequently, the helper variable is not included in the set of optimization variables. However, as we progress through this manual, we will activate the generator, introducing the helper variable and additional constraints to the optimization model.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is worth emphasizing that in instances where a linear piecewise cost function consists of only a single segment, as demonstrated by the reactive power output cost of Generator 2, the function is modeled as a standard linear function, obviating the need for additional helper optimization variables.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Please be aware that JuliaGrid maintains references to all variables, which are categorized into six fields:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.variable))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Variable-Names","page":"AC Optimal Power Flow","title":"Variable Names","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the option to define custom variable names for printing and writing equations, which can help present them in a more compact form. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(system, Ipopt.Optimizer; magnitude = \"V\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-Variables","page":"AC Optimal Power Flow","title":"Add Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The user has the ability to easily add new variables to the defined AC optimal power flow model by using the @variable macro from the JuMP package:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.@variable(analysis.method.jump, newVariable)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can verify that the new variable is included in the defined model by using the function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Delete-Variables","page":"AC Optimal Power Flow","title":"Delete Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The variable can be deleted, but this operation is only applicable if the objective function is either affine or quadratic. To achieve this, we can utilize the delete function provided by the JuMP, as demonstrated below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After deletion, the variable is no longer part of the model:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#DCConstraintFunctionsManual","page":"AC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid keeps track of all the references to internally formed constraints in the constraint field of the ACOptimalPowerFlow type. These constraints are divided into six fields:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.constraint))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nWe suggest that readers refer to the tutorial on AC Optimal Power Flow for insights into the implementation.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Slack-Bus-Constraint","page":"AC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The slack field contains a reference to the equality constraint associated with the fixed bus voltage angle value of the slack bus. This constraint is set within the addBus! function using the angle keyword:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the flexibility to modify this constraint by changing which bus serves as the slack bus and by adjusting the value of the bus angle. This can be achieved using the updateBus! function, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", type = 1)\nupdateBus!(system, analysis; label = \"Bus 2\", type = 3, angle = -0.2)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated slack constraint can be inspected as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Bus-Power-Balance-Constraints","page":"AC Optimal Power Flow","title":"Bus Power Balance Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The balance field contains references to the equality constraints associated with the active and reactive power balance equations defined for each bus. These constraints ensure that the total active and reactive power injected by the generators matches the total active and reactive power demanded at each bus.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term in the active power balance equations is determined by the active keyword within the addBus! function, which defines the active power demanded at the bus. We can access the references to the active power balance constraints using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the constant term in the reactive power balance equations is determined by the reactive keyword within the addBus! function, which defines the reactive power demanded at the bus. We can access the references to the reactive power balance constraints using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"During the execution of functions that add or update power system components, these constraints are automatically adjusted to reflect the current configuration of the power system, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", active = 0.5)\nupdateBranch!(system, analysis; label = \"Branch 1\", reactance = 0.25)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The updated set of active power balance constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Bus-Voltage-Constraints","page":"AC Optimal Power Flow","title":"Bus Voltage Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The voltage field contains references to the inequality constraints associated with the voltage magnitude and voltage angle difference limits. These constraints ensure that the bus voltage magnitudes and the angle differences between the from-bus and to-bus ends of each branch are within specified limits.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The minimum and maximum bus voltage magnitude limits are set using the minMagnitude and maxMagnitude keywords within the addBus! function. The constraints associated with these limits can be accessed using:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.voltage.magnitude)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The minimum and maximum voltage angle difference limits between the from-bus and to-bus ends of each branch are set using the minDiffAngle and maxDiffAngle keywords within the addBranch! function. The constraints associated with these limits can be accessed using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nPlease note that if the limit constraints are set to minDiffAngle = -2π and maxDiffAngle = 2π for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, by employing the updateBus! and updateBranch! functions, the user has the ability to modify these specific constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", minMagnitude = 1.0, maxMagnitude = 1.0)\nupdateBranch!(system, analysis; label = \"Branch 1\", minDiffAngle = -1.7, maxDiffAngle = 1.7)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated set of constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.voltage.magnitude)\nprint(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACBranchFlowConstraintsManual","page":"AC Optimal Power Flow","title":"Branch Flow Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The flow field contains references to the inequality constraints associated with the apparent power flow, active power flow, or current flow magnitude limits at the from-bus and to-bus ends of each branch. The type to which one of the constraints will be applied is defined according to the type keyword within the addBranch! function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"type = 1 for the apparent power flow,\ntype = 2 for the active power flow,\ntype = 3 for the current flow magnitude.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These limits are specified using the minFromBus, maxFromBus, minToBus and maxToBus keywords within the addBranch! function. By default, these limit keywords are associated with apparent power (type = 1).","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"However, in the example, we configured it to use active power flow by setting type = 2. To access the flow constraints of branches at the from-bus end, we can utilize the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.from)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nIf the branch flow limits are set to minFromBus = 0.0 and maxFromBus = 0.0 for the corresponding branch, JuliGrid will omit the corresponding inequality constraint at the from-bus end of the branch. The same applies to the to-bus end if minToBus = 0.0 and maxToBus = 0.0 are set.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, by employing the updateBranch! function, we have the ability to modify these specific constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", minFromBus = -0.15, maxToBus = 0.15)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The updated set of flow constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.from)\nprint(system.branch.label, analysis.method.constraint.flow.to)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"tip: Tip\nIn typical scenarios, minFromBus is equal to minToBus, and maxFromBus is equal to maxToBus. However, we allow these values to be defined separately for greater flexibility, enabling, among other things, the option to apply constraints on only one side of the branch.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Generator-Power-Capability-Constraints","page":"AC Optimal Power Flow","title":"Generator Power Capability Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The capability field contains references to the inequality constraints associated with the minimum and maximum active and reactive power outputs of the generators.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constraints associated with the minimum and maximum active power output limits of the generators are defined using the minActive and maxActive keywords within the addGenerator! function. To access the constraints associated with these limits, we can use the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the constraints associated with the minimum and maximum reactive power output limits of the generators are specified using the minReactive and maxReactive keywords within the addGenerator! function. To access these constraints, we can use the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As demonstrated, the active and reactive power outputs of Generator 1 and Generator 2 are currently fixed at zero due to previous actions that set these generators out-of-service. However, we can modify these specific constraints by utilizing the updateGenerator! function, as shown below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 1\", status = 1)\nupdateGenerator!(system, analysis; label = \"Generator 2\", status = 1, minActive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated set of constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)\nprint(system.generator.label, analysis.method.constraint.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nThis representation may not fully capture the generator's power output behavior due to the tradeoff between active and reactive power outputs. JuliaGrid can incorporate this tradeoff in its optimization model. For more information, see the tutorial on Power Capability Constraints.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Power-Piecewise-Constraints","page":"AC Optimal Power Flow","title":"Power Piecewise Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the context of cost modeling, the piecewise field acts as a reference to the inequality constraints associated with linear piecewise cost functions. These constraints are established using the cost! function, with active = 1 or reactive = 1 specified when working with linear piecewise cost functions that consist of multiple segments.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In our example, only the active power cost of Generator 2 is modeled as a linear piecewise function with two segments, and JuliaGrid takes care of setting up the appropriate inequality constraints for each segment:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.piecewise.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is worth noting that these constraints can also be automatically updated using the cost! function. Readers can find more details in the section discussing the objective function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As mentioned at the beginning, linear piecewise cost functions with multiple segments will also introduce helper variables that are added to the objective function. In this specific example, the helper variable is:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.variable.actwise[2]","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-Constraints","page":"AC Optimal Power Flow","title":"Add Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can effortlessly introduce additional constraints into the defined AC optimal power flow model by utilizing the addBranch! or addGenerator! functions. Specifically, if a user wishes to include a new branch or generator in an already defined PowerSystem and ACOptimalPowerFlow type:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"addBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\naddGenerator!(system, analysis; label = \"Generator 3\", bus = \"Bus 2\", active = 2, status = 1)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"This will affect all constraints related to branches and generators, but it will also update balance constraints to configure the optimization model to match the current state of the power system. For example, we can observe the following updated constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)\nprint(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-User-Defined-Constraints","page":"AC Optimal Power Flow","title":"Add User-Defined Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users also have the option to include their custom constraints within the established AC optimal power flow model by employing the @constraint macro. For example, the addition of a new constraint can be achieved as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.@constraint(analysis.method.jump, 0.0 <= analysis.method.variable.active[3] <= 0.3)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Delete-Constraints","page":"AC Optimal Power Flow","title":"Delete Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To delete a constraint, users can make use of the delete function from the JuMP package. When handling constraints that have been internally created, users can refer to the constraint references stored in the constraint field of the ACOptimalPowerFlow type.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For example, if the intention is to eliminate constraints related to the capability of Generator 3, we can use:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, analysis.method.constraint.capability.active[3])\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nIn the event that a user deletes a constraint and subsequently executes a function that updates bus, branch, or generator parameters, and if the deleted constraint is affected by these functions, JuliaGrid will automatically reinstate that constraint. Users should exercise caution when deleting constraints, as this action is considered potentially harmful since it operates independently of power system data.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACObjectiveFunctionManual","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The objective function of the AC optimal power flow is formulated using polynomial and linear piecewise cost functions associated with the generators, defined using the cost! functions.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the provided example, the objective function to be minimized in order to obtain optimal values for the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles, is as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid also stores the objective function in a separate variable, which can be accessed by referring to the variable analysis.objective. In this variable, the objective function is organized in a way that separates the quadratic and nonlinear components of the objective function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Update-Objective-Function","page":"AC Optimal Power Flow","title":"Update Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By utilizing the cost! functions, users have the flexibility to modify the objective function by adjusting polynomial or linear piecewise coefficients or by changing the type of polynomial or linear piecewise function employed. For example, consider Generator 1, which employs a quadratic polynomial cost function for active power. We can redefine the cost function for this generator as a cubic polynomial and thereby define a nonlinear objective function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"cost!(system, analysis; label = \"Generator 1\", active = 2, polynomial = [631; 257; 40; 5.0])\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"This leads to an updated objective function, which can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#User-Defined-Objective-Function","page":"AC Optimal Power Flow","title":"User-Defined Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can modify the objective function using the set_objective_function function from the JuMP package. This operation is considered destructive because it is independent of power system data; however, in certain scenarios, it may be more straightforward than using the cost! function for updates. Moreover, using this methodology, users can combine a defined function with a newly defined expression.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this context, we can utilize the saved objective function within the objective field of the ACOptimalPowerFlow type. For example, we can easily eliminate nonlinear parts and alter the quadratic component of the objective:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"expr = 5.0 * analysis.method.variable.active[1] * analysis.method.variable.active[1]\nJuMP.set_objective_function(analysis.method.jump, analysis.method.objective.quadratic - expr)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can now observe the updated objective function as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACSetupPrimalStartingValuesManual","page":"AC Optimal Power Flow","title":"Setup Starting Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In JuliaGrid, the assignment of starting primal and dual values for optimization variables and constraints takes place when the solve! function is executed.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Starting-Primal-Values","page":"AC Optimal Power Flow","title":"Starting Primal Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Starting primal values are determined based on the generator and voltage fields within the ACOptimalPowerFlow type. By default, these values are initially established using the active and reactive power outputs of the generators and the initial bus voltage magnitudes and angles:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"generator = analysis.power.generator;\nprint(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the flexibility to adjust these values according to their specifications, which will then be used as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Using-AC-Power-Flow","page":"AC Optimal Power Flow","title":"Using AC Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this perspective, users have the capability to conduct the AC power flow analysis and leverage the resulting solution to configure starting primal values. Here is an illustration of how this can be achieved:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"flow = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, flow)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, flow)\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the solution, we can calculate the active and reactive power outputs of the generators and utilize the bus voltage magnitudes and angles to set the starting values. In this case, the generator and voltage fields of the ACOptimalPowerFlow type can be employed to store the new starting values:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"for (key, idx) in system.generator.label\n active, reactive = generatorPower(system, flow; label = key)\n analysis.power.generator.active[idx] = active\n analysis.power.generator.reactive[idx] = reactive\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = flow.voltage.magnitude[i]\n analysis.voltage.angle[i] = flow.voltage.angle[i]\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Starting-Dual-Values","page":"AC Optimal Power Flow","title":"Starting Dual Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Dual variables, often referred to as Lagrange multipliers or Kuhn-Tucker multipliers, represent the shadow prices or marginal costs associated with constraints. The assignment of initial dual values occurs when the solve! function is executed. Initially, the starting dual values are unknown, but users can access and manually set them. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.dual.balance.active[1] = 0.4\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowSolutionManual","page":"AC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To establish the AC optimal power flow problem, we can utilize the acOptimalPowerFlow function. After setting up the problem, we can use the solve! function to compute the optimal values for the active and reactive power outputs of the generators and the bus voltage magnitudes angles. Also, to turn off the solver output within the REPL, we use the set_silent function before calling solve! function. Here is an example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By executing this function, we will obtain the solution with the optimal values for the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"generator = analysis.power.generator;\nprint(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Objective-Value","page":"AC Optimal Power Flow","title":"Objective Value","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the objective value of the optimal power flow solution, we can use the objective_value function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_value(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Dual-Variables","page":"AC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The values of the dual variables are stored in the dual field of the ACOptimalPowerFlow type. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.dual.balance.active[1]","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Print-Results-in-the-REPL","page":"AC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can utilize the functions printBusData and printGeneratorData to display results. Additionally, the functions listed in the Print Constraint Data section allow users to print constraint data related to buses, branches, or generators in the desired units. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"@power(MW, MVAr, pu)\nshow = Dict(\"Active Power Balance\" => false)\nprintBusConstraint(system, analysis; show)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, users can easily customize the print results for specific constraint, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"printBusConstraint(system, analysis; label = \"Bus 1\", header = true)\nprintBusConstraint(system, analysis; label = \"Bus 2\", footer = true)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Save-Results-to-a-File","page":"AC Optimal Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusConstraint(system, analysis, file)\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Save-Results-to-a-CSV-File","page":"AC Optimal Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusConstraint(system, analysis, io; style = false)\nCSV.write(\"constraint.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Primal-and-Dual-Warm-Start","page":"AC Optimal Power Flow","title":"Primal and Dual Warm Start","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Utilizing the ACOptimalPowerFlow type and proceeding directly to the solver offers the advantage of a \"warm start\". In this scenario, the starting primal and dual values for the subsequent solving step correspond to the solution obtained from the previous step.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Primal-Variables","page":"AC Optimal Power Flow","title":"Primal Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the previous example, the following solution was obtained, representing the values of the primal variables:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Dual-Variables-2","page":"AC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We also obtained all dual values. Here, we list only the dual variables for one type of constraint as an example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.dual.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Modify-Optimal-Power-Flow","page":"AC Optimal Power Flow","title":"Modify Optimal Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Now, let us introduce changes to the power system from the previous example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", maxActive = 0.08)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, we want to solve this modified optimal power flow problem. If we use solve! at this point, the primal and dual starting values will be set to the previously obtained values:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"solve!(system, analysis)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As a result, we obtain a new solution:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Reset-Primal-and-Dual-Values","page":"AC Optimal Power Flow","title":"Reset Primal and Dual Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users retain the flexibility to reset initial primal values to their default configurations at any juncture. This can be accomplished by utilizing the active and reactive power outputs of the generators and the initial bus voltage magnitudes and angles extracted from the PowerSystem type, employing the startingPrimal! function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"startingPrimal!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The primal starting values will now be identical to those that would be obtained if the acOptimalPowerFlow function were executed after all the updates have been applied.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Using the startingDual! function, users can clear all dual variable values, resetting them to their default state:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"startingDual!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerCurrentAnalysisManual","page":"AC Optimal Power Flow","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the solution from the AC optimal power flow, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the power system for which we obtained the AC optimal power flow solution:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid, JuMP # hide\nusing Ipopt\n\n@default(unit) # hide\n@default(template) # hide\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.9, maxMagnitude = 1.1)\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.05, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, reactive = 0.01, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05, reactive = 0.02)\n\n@branch(resistance = 0.5, reactance = 1.0, conductance = 1e-4, susceptance = 0.01)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", maxFromBus = 0.15)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", maxFromBus = 0.10)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", maxFromBus = 0.25)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, reactive = 0.1)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can now utilize the following functions to calculate powers and currents:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For instance, if we want to show the active power injections and the from-bus current magnitudes, we can employ:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.magnitude)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nTo better understand the powers and current associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on AC Optimal Power Flow.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Print-Results-in-the-REPL-2","page":"AC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus data with the desired units, users can use the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nshow = Dict(\"Power Generation\" => false, \"Current Injection\" => false)\nprintBusData(system, analysis; show)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Injection","page":"AC Optimal Power Flow","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC Optimal Power Flow","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Flow","page":"AC Optimal Power Flow","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the total active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Injection","page":"AC Optimal Power Flow","title":"Current Injection","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Flow","page":"AC Optimal Power Flow","title":"Current Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by using:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Through-Series-Impedance","page":"AC Optimal Power Flow","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"api/setupPrint/#setupPrintAPI","page":"Setup and Print","title":"Setup and Print","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"For further information on this topic, please see the Power System Model or Measurement Model sections of the Manual. Please note that when using macros, they modify variables within the current scope. Print functions can be used to print results to the REPL, or users can redirect the output to print results to a text file, for example.","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"using JuliaGrid","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Base-Units","page":"Setup and Print","title":"Base Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@base","category":"page"},{"location":"api/setupPrint/#Input-Units","page":"Setup and Print","title":"Input Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@power\n@voltage\n@current\n@parameter","category":"page"},{"location":"api/setupPrint/#Label-Types","page":"Setup and Print","title":"Label Types","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@labels","category":"page"},{"location":"api/setupPrint/#Default-Settings","page":"Setup and Print","title":"Default Settings","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@default","category":"page"},{"location":"api/setupPrint/#Print-Power-System-Data","page":"Setup and Print","title":"Print Power System Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusData\nprintBranchData\nprintGeneratorData","category":"page"},{"location":"api/setupPrint/#Print-Power-System-Summary","page":"Setup and Print","title":"Print Power System Summary","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusSummary\nprintBranchSummary\nprintGeneratorSummary","category":"page"},{"location":"api/setupPrint/#Print-Measurement-Data","page":"Setup and Print","title":"Print Measurement Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printVoltmeterData\nprintAmmeterData\nprintWattmeterData\nprintVarmeterData\nprintPmuData","category":"page"},{"location":"api/setupPrint/#Print-Constraint-Data","page":"Setup and Print","title":"Print Constraint Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusConstraint\nprintBranchConstraint\nprintGeneratorConstraint","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Base-Units-2","page":"Setup and Print","title":"Base Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@base","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@base","page":"Setup and Print","title":"JuliaGrid.@base","text":"@base(system::PowerSystem, power, voltage)\n\nBy default, the units for base power and base voltages are set to volt-ampere (VA) and volt (V), but you can modify the prefixes using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of power (VA) or unit of voltage (V). Keep in mind that the macro must be used after creating the composite type PowerSystem.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n@base(system, MVA, kV)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Input-Units-2","page":"Setup and Print","title":"Input Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@power\n@voltage\n@current\n@parameter","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@power","page":"Setup and Print","title":"JuliaGrid.@power","text":"@power(active, reactive, apparent)\n\nJuliaGrid stores all data related with powers in per-units, and these cannot be altered. However, the power units of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of active power (W), reactive power (VAr), or apparent power (VA). Also, it is a possible to combine SI units with/without prefixes with per-units (pu).\n\nChanging the unit of active power is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: active, conductance;\naddBranch!, updateBranch!, @branch: if type = 2: minFromBus, maxFromBus, minToBus, maxToBus;\naddGenerator!, updateGenerator!, @generator: active, minActive, maxActive, lowActive, upActive, loadFollowing, reserve10min, reserve30min;\ncost!: if active: piecewise, polynomial;\naddWattmeter!, updateWattmeter!: active, variance;\n@wattmeter: , varianceBus, varianceFrom, varianceTo.\n\nChanging the unit of reactive power unit is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: reactive, susceptance;\naddGenerator!, updateGenerator!, @generator: reactive, minReactive, maxReactive, minLowReactive, maxLowReactive, minUpReactive, maxUpReactive, reactiveRamp;\ncost!: if reactive: piecewise, polynomial;\naddVarmeter!, updateVarmeter!: reactive, variance;\n@varmeter: varianceBus, varianceFrom, varianceTo.\n\nChanging the unit of apparent power unit is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: if type = 1: minFromBus, maxFromBus, minToBus, maxToBus.\n\nExample\n\n@power(MW, kVAr, VA)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@voltage","page":"Setup and Print","title":"JuliaGrid.@voltage","text":"@voltage(magnitude, angle, base)\n\nJuliaGrid stores all data related with voltages in per-units and radians, and these cannot be altered. However, the voltage magnitude and angle units of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nThe prefixes must adhere to the SI prefixes and should be specified along with the unit of voltage, either magnitude (V) or base (V). Alternatively, the unit of voltage magnitude can be expressed in per-unit (pu). The unit of voltage angle should be in radians (rad) or degrees (deg).\n\nChanging the unit of voltage magnitude is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: magnitude, minMagnitude, maxMagnitude;\naddGenerator!, updateGenerator!, @generator: magnitude;\naddVoltmeter!, updateVoltmeter!, @voltmeter: magnitude, variance;\naddPmu!, updatePmu!: if bus: magnitude, varianceMagnitude;\n@pmu: varianceMagnitudeBus.\n\nChanging the unit of voltage angle is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: angle;\naddBranch!, updateBranch!, @branch: shiftAngle, minDiffAngle, maxDiffAngle;\naddPmu!, updatePmu!: if bus: angle, varianceAngle;\n@pmu: varianceAngleBus.\n\nChanging the unit prefix of voltage base is reflected in the following quantity:\n\naddBus!, updateBus!, @bus: base.\n\nExample\n\n@voltage(pu, deg, kV)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@current","page":"Setup and Print","title":"JuliaGrid.@current","text":"@current(magnitude, angle)\n\nJuliaGrid stores all data related with currents in per-units and radians, and these cannot be altered. However, the current magnitude and angle units of the built-in functions used to add or modified measurement devices can be modified using the macro.\n\nThe prefixes must adhere to the SI prefixes and should be specified along with the unit of current magnitude (V). Alternatively, the unit of current magnitude can be expressed in per-unit (pu). The unit of current angle should be in radians (rad) or degrees (deg).\n\nChanging the unit of current magnitude is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: if type = 3: minFromBus, maxFromBus, minToBus, maxToBus.\naddAmmeter!, updateAmmeter!: magnitude, variance;\n@ammeter: varianceFrom, varianceTo;\naddPmu!, updatePmu!: if from or to: magnitude, varianceMagnitude;\n@pmu: varianceMagnitudeFrom, varianceMagnitudeTo.\n\nChanging the unit of current angle is reflected in the following quantities:\n\naddPmu!, updatePmu!: if from or to: angle, varianceAngle;\n@pmu: varianceAngleFrom, varianceAngleTo.\n\nExample\n\n@current(pu, deg)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@parameter","page":"Setup and Print","title":"JuliaGrid.@parameter","text":"@parameter(impedance, admittance)\n\nJuliaGrid stores all data related with impedances and admittancies in per-units, and these cannot be altered. However, units of impedance and admittance of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of impedance (Ω) or unit of admittance (S). The second option is to define the units in per-unit (pu).\n\nIn the case where impedance and admittance are being used in SI units (Ω and S) and these units are related to the transformer, the assignment must be based on the primary side of the transformer.\n\nChanging the units of impedance is reflected in the following quantities in specific functions:\n\naddBranch!, updateBranch!, @branch: resistance, reactance.\n\nChanging the units of admittance is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: conductance, susceptance.\n\nExample\n\n@parameter(Ω, pu)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Label-Types-2","page":"Setup and Print","title":"Label Types","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@labels","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@labels","page":"Setup and Print","title":"JuliaGrid.@labels","text":"@labels(type)\n\nJuliaGrid keeps all labels in ordered dictionaries as Strings. Users have the option to use Integers instead, which can be a more efficient way to store labels, particularly for large-scale systems.\n\nExample\n\n@labels(Integer)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Default-Settings-2","page":"Setup and Print","title":"Default Settings","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@default","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@default","page":"Setup and Print","title":"JuliaGrid.@default","text":"@default(mode)\n\nThe macro is designed to reset various settings to their default values.\n\nThe mode argument can take on the following values:\n\nunit: Resets all units to their default settings.\npower: Sets active, reactive, and apparent power to per-units.\nvoltage: Sets voltage magnitude to per-unit and voltage angle to radian.\nparameter: Sets impedance and admittance to per-units.\ntemplate: Resets bus, branch, generator, voltmeter, ammeter, wattmeter, varmeter, and pmu templates to their default settings.\nbus: Resets the bus template to its default settings.\nbranch: Resets the branch template to its default settings.\ngenerator: Resets the generator template to its default settings.\nvoltmeter: Resets the voltmeter template to its default settings.\nammeter: Resets the ammeter template to its default settings.\nwattmeter: Resets the wattmeter template to its default settings.\nvarmeter: Resets the varmeter template to its default settings.\npmu: Resets the pmu template to its default settings.\n\nExample\n\n@default(unit)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintPowerSystemDataAPI","page":"Setup and Print","title":"Print Power System Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusData\nprintBranchData\nprintGeneratorData","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusData","page":"Setup and Print","title":"JuliaGrid.printBusData","text":"printBusData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints voltages, powers, and currents related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding bus.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all buses\nfmt = Dict(\"Power Demand\" => \"%.2f\", \"Voltage Magnitude\" => \"%.2f\", \"Label\" => \"%s\")\nshow = Dict(\"Power Injection\" => false, \"Power Generation Reactive\" => false)\nprintBusData(system, analysis; fmt, show, repeat = 10)\n\n# Print data for specific buses\ndelimiter = \" \"\nwidth = Dict(\"Voltage\" => 9, \"Power Injection Active\" => 9)\nprintBusData(system, analysis; label = 2, delimiter, width, title = true, header = true)\nprintBusData(system, analysis; label = 10, delimiter, width)\nprintBusData(system, analysis; label = 12, delimiter, width)\nprintBusData(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchData","page":"Setup and Print","title":"JuliaGrid.printBranchData","text":"printBranchData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints powers and currents related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding branch.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all branches\nfmt = Dict(\"Shunt Power\" => \"%.2f\", \"Series Power Reactive\" => \"%.2f\")\nshow = Dict(\"From-Bus Power\" => false, \"To-Bus Power Reactive\" => false)\nprintBranchData(system, analysis; fmt, show, repeat = 11, title = false)\n\n# Print data for specific branches\ndelimiter = \" \"\nwidth = Dict(\"From-Bus Power\" => 9, \"To-Bus Power Active\" => 9)\nprintBranchData(system, analysis; label = 2, delimiter, width, header = true)\nprintBranchData(system, analysis; label = 10, delimiter, width)\nprintBranchData(system, analysis; label = 12, delimiter, width)\nprintBranchData(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorData","page":"Setup and Print","title":"JuliaGrid.printGeneratorData","text":"printGeneratorData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints powers related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding generator.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all generators\nfmt = Dict(\"Power Output Active\" => \"%.2f\")\nshow = Dict(\"Power Output Reactive\" => false)\nprintGeneratorData(system, analysis; fmt, show, title = false)\n\n# Print data for specific generators\ndelimiter = \" \"\nwidth = Dict(\"Power Output Active\" => 7)\nprintGeneratorData(system, analysis; label = 1, delimiter, width, header = true)\nprintGeneratorData(system, analysis; label = 4, delimiter, width)\nprintGeneratorData(system, analysis; label = 5, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintPowerSystemSummaryAPI","page":"Setup and Print","title":"Print Power System Summary","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusSummary\nprintBranchSummary\nprintGeneratorSummary","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusSummary","page":"Setup and Print","title":"JuliaGrid.printBusSummary","text":"printBusSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style)\n\nThe function prints a summary of the electrical quantities related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"In-Use\" => false)\nprintBusSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchSummary","page":"Setup and Print","title":"JuliaGrid.printBranchSummary","text":"printBranchSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style))\n\nThe function prints a summary of the electrical quantities related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"Total\" => false)\nprintBranchSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorSummary","page":"Setup and Print","title":"JuliaGrid.printGeneratorSummary","text":"printGeneratorSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style)\n\nThe function prints a summary of the electrical quantities related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"Minimum\" => false)\nprintGeneratorSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Print-Measurement-Data-2","page":"Setup and Print","title":"Print Measurement Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printVoltmeterData\nprintAmmeterData\nprintWattmeterData\nprintVarmeterData\nprintPmuData","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printVoltmeterData","page":"Setup and Print","title":"JuliaGrid.printVoltmeterData","text":"printVoltmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to voltmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding voltmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all voltmeters\nfmt = Dict(\"Voltage Magnitude\" => \"%.2f\", \"Voltage Magnitude Estimate\" => \"%.6f\")\nshow = Dict(\"Voltage Magnitude Residual\" => false)\nprintVoltmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific voltmeters\nwidth = Dict(\"Voltage Magnitude Estimate\" => 11)\nprintVoltmeterData(system, device, analysis; label = 1, width, header = true)\nprintVoltmeterData(system, device, analysis; label = 6, width)\nprintVoltmeterData(system, device, analysis; label = 8, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printAmmeterData","page":"Setup and Print","title":"JuliaGrid.printAmmeterData","text":"printAmmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to ammeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding ammeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\ncurrent!(system, analysis)\n\n# Print data for all ammeters\nfmt = Dict(\"Current Magnitude\" => \"%.2f\", \"Current Magnitude Estimate\" => \"%.6f\")\nshow = Dict(\"Current Magnitude Residual\" => false)\nprintAmmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific ammeters\nwidth = Dict(\"Current Magnitude\" => 10)\nprintAmmeterData(system, device, analysis; label = \"From 1\", width, header = true)\nprintAmmeterData(system, device, analysis; label = \"From 4\", width)\nprintAmmeterData(system, device, analysis; label = \"From 6\", width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printWattmeterData","page":"Setup and Print","title":"JuliaGrid.printWattmeterData","text":"printWattmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to wattmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding wattmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all wattmeters\nfmt = Dict(\"Active Power\" => \"%.2f\", \"Active Power Estimate\" => \"%.6f\")\nshow = Dict(\"Active Power Status\" => false)\nprintWattmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 14)\n\n# Print data for specific wattmeters\nwidth = Dict(\"Active Power Residual\" => 11)\nprintWattmeterData(system, device, analysis; label = 2, width, header = true)\nprintWattmeterData(system, device, analysis; label = 5, width)\nprintWattmeterData(system, device, analysis; label = 9, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printVarmeterData","page":"Setup and Print","title":"JuliaGrid.printVarmeterData","text":"printVarmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to varmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding varmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all wattmeters\nfmt = Dict(\"Reactive Power\" => \"%.2f\", \"Reactive Power Estimate\" => \"%.6f\")\nshow = Dict(\"Reactive Power Status\" => false)\nprintVarmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 14)\n\n# Print data for specific wattmeters\nwidth = Dict(\"Reactive Power Residual\" => 11)\nprintVarmeterData(system, device, analysis; label = 2, width, header = true)\nprintVarmeterData(system, device, analysis; label = 5, width)\nprintVarmeterData(system, device, analysis; label = 9, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printPmuData","page":"Setup and Print","title":"JuliaGrid.printPmuData","text":"printPmuData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to PMUs. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding PMU.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printPmuData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\ncurrent!(system, analysis)\n\n# Print data for all PMUs\nfmt = Dict(\"Current Magnitude\" => \"%.2f\", \"Current Magnitude Variance\" => \"%.5f\")\nshow = Dict(\"Current Angle\" => false, \"Current Magnitude Status\" => false)\nprintPmuData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific PMUs\nwidth = Dict(\"Current Magnitude\" => 10, \"Current Angle Status\" => 8)\nprintPmuData(system, device, analysis; label = \"From 1\", width, header = true)\nprintPmuData(system, device, analysis; label = \"From 4\", width)\nprintPmuData(system, device, analysis; label = \"From 6\", width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintConstraintDataAPI","page":"Setup and Print","title":"Print Constraint Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusConstraint\nprintBranchConstraint\nprintGeneratorConstraint","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusConstraint","page":"Setup and Print","title":"JuliaGrid.printBusConstraint","text":"printBusConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding bus.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all buses\nfmt = Dict(\"Active Power Balance\" => \"%.2e\", \"Reactive Power Balance Dual\" => \"%.4e\")\nshow = Dict(\"Voltage Magnitude\" => false, \"Reactive Power Balance Solution\" => false)\nprintBusConstraint(system, analysis; fmt, show, repeat = 10)\n\n# Print data for specific buses\ndelimiter = \" \"\nwidth = Dict(\"Voltage Magnitude\" => 8, \"Active Power Balance Solution\" => 12)\nprintBusConstraint(system, analysis; label = 2, delimiter, width, header = true)\nprintBusConstraint(system, analysis; label = 10, delimiter, width)\nprintBusConstraint(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchConstraint","page":"Setup and Print","title":"JuliaGrid.printBranchConstraint","text":"printBranchConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding branch.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nupdateBranch!(system; label = 3, minDiffAngle = 0.05, maxDiffAngle = 1.5)\nupdateBranch!(system; label = 4, minDiffAngle = 0.05, maxDiffAngle = 1.1)\nupdateBranch!(system; label = 4, maxFromBus = 0.4, maxToBus = 0.5)\nupdateBranch!(system; label = 9, minFromBus = 0.1, maxFromBus = 0.3)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all branches\nfmt = Dict(\"Voltage Angle Difference\" => \"%.2f\")\nshow = Dict(\"To-Bus Apparent Power Flow Dual\" => false)\nprintBranchConstraint(system, analysis; fmt, show, repeat = 2)\n\n# Print data for specific branches\ndelimiter = \" \"\nwidth = Dict(\"From-Bus Apparent Power Flow\" => 13, \"Voltage Angle Difference Dual\" => 12)\nprintBranchConstraint(system, analysis; label = 3, delimiter, width, header = true)\nprintBranchConstraint(system, analysis; label = 4, delimiter, width)\nprintBranchConstraint(system, analysis; label = 9, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorConstraint","page":"Setup and Print","title":"JuliaGrid.printGeneratorConstraint","text":"printGeneratorConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding generator.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all generators\nfmt = Dict(\"Active Power Capability\" => \"%.2f\")\nshow = Dict(\"Reactive Power Capability\" => false, \"Active Power Capability Dual\" => false)\nprintGeneratorConstraint(system, analysis; fmt, show, repeat = 3)\n\n# Print data for specific generators\ndelimiter = \" \"\nwidth = Dict(\"Active Power Capability\" => 11, \"Reactive Power Capability Dual\" => 10)\nprintGeneratorConstraint(system, analysis; label = 2, delimiter, width, header = true)\nprintGeneratorConstraint(system, analysis; label = 3, delimiter, width)\nprintGeneratorConstraint(system, analysis; label = 5, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#StateEstimationAPI","page":"State Estimation","title":"State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"For further information on this topic, please see the AC State Estimation, PMU State Estimation or DC State Estimation sections of the Manual. Below, we have provided a list of functions that can be utilized for state estimation, observability analysis, or bad data processing.","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"To load state estimation API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"using JuliaGrid","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Observability-Analysis","page":"State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"islandTopologicalFlow\nislandTopological\nrestorationGram!","category":"page"},{"location":"api/stateEstimation/#AC-State-Estimation","page":"State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"gaussNewton\nacLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#PMU-State-Estimation","page":"State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"pmuPlacement\npmuStateEstimation\npmuLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#DC-State-Estimation","page":"State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"dcStateEstimation\ndcLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#Bad-Data-Analysis","page":"State Estimation","title":"Bad Data Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"residualTest!","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Observability-Analysis-2","page":"State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"islandTopologicalFlow(::PowerSystem, ::Measurement)\nislandTopological(::PowerSystem, ::Measurement)\nrestorationGram!(::PowerSystem, ::Measurement, ::Measurement, ::Island)","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.islandTopologicalFlow-Tuple{PowerSystem, Measurement}","page":"State Estimation","title":"JuliaGrid.islandTopologicalFlow","text":"islandTopologicalFlow(system::PowerSystem, device::Measurement)\n\nThe function utilizes a topological approach to detect flow observable islands, resulting in the formation of disconnected and loop-free subgraphs. It is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.\n\nArguments\n\nTo define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.\n\nReturns\n\nThe function returns an Island type, containing information about the islands:\n\nisland: List enumerating observable islands with indices of buses.\nbus: Positions of buses in relation to each island.\ntie: Tie data associated with buses and branches.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 15)\ndevice.varmeter.reactive.status = copy(device.wattmeter.active.status)\n\nislands = islandTopologicalFlow(system, device)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/#JuliaGrid.islandTopological-Tuple{PowerSystem, Measurement}","page":"State Estimation","title":"JuliaGrid.islandTopological","text":"islandTopological(system::PowerSystem, meter::Measurement)\n\nThe function employs a topological method to identify maximal observable islands. Specifically, it employs active power measurements to pinpoint flow observable islands. Subsequently, these islands are merged based on the available injection measurements.\n\nIt is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.\n\nArguments\n\nTo define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.\n\nReturns\n\nThe function returns an Island type, containing information about the islands:\n\nisland: List enumerating observable islands with indices of buses.\nbus: Positions of buses in relation to each island.\ntie: Tie data associated with buses and branches.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 15)\ndevice.varmeter.reactive.status = copy(device.wattmeter.active.status)\n\nislands = islandTopological(system, device)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/#JuliaGrid.restorationGram!-Tuple{PowerSystem, Measurement, Measurement, Island}","page":"State Estimation","title":"JuliaGrid.restorationGram!","text":"restorationGram!(system::PowerSystem, device::Measurement, pseudo::Measurement,\n islands::Island; threshold)\n\nUpon identifying the islands, the function incorporates measurements from the available pseudo-measurements in the pseudo variable into the device variable to reinstate observability. This method relies on reduced coefficient matrices and the Gram matrix.\n\nIt is important to note that the device labels in the device and pseudo variables must be different to enable the function to successfully incorporate measurements from pseudo into the device set of measurements.\n\nKeyword\n\nThe keyword threshold defines the zero pivot threshold value, with a default value of 1e-5. More precisely, all computed pivots less than this value will be treated as zero pivots.\n\nUpdates\n\nThe function updates the device variable of the Measurement composite type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\npseudo = measurement(\"pseudomeasurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 10)\nislands = islandTopological(system, device)\n\nrestorationGram!(system, device, pseudo, islands)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#AC-State-Estimation-2","page":"State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"gaussNewton\nacLavStateEstimation\nsolve!(::PowerSystem, ::ACStateEstimation{NonlinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.gaussNewton","page":"State Estimation","title":"JuliaGrid.gaussNewton","text":"gaussNewton(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function sets up the Gauss-Newton method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates. The Gauss-Newton method throughout iterations provided WLS estimator.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the nonlinear WLS state estimation framework.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the ACStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the AC state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\n\nSet up the AC state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.acLavStateEstimation","page":"State Estimation","title":"JuliaGrid.acLavStateEstimation","text":"acLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function sets up the LAV method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the ACStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, ACStateEstimation{NonlinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACStateEstimation)\n\nBy computing the bus voltage magnitudes and angles, the function solves the AC state estimation model.\n\nUpdates\n\nThe resulting bus voltage magnitudes and angles are stored in the voltage field of the ACStateEstimation type.\n\nExamples\n\nSolving the AC state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\nSolving the AC state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#PMU-State-Estimation-2","page":"State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"pmuPlacement\npmuStateEstimation\npmuLavStateEstimation\nsolve!(::PowerSystem, ::PMUStateEstimation{LinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.pmuPlacement","page":"State Estimation","title":"JuliaGrid.pmuPlacement","text":"pmuPlacement(system::PowerSystem, optimizer; bridge)\n\nThe function determines the optimal placement of PMUs through integer linear programming. Specifically, it identifies the minimum set of PMU locations required for effective power system state estimation, ensuring observability with the least number of PMUs.\n\nThe function accepts a PowerSystem composite type as input to establish the framework for finding the optimal PMU placement. If the ac field within the PowerSystem composite type is not yet created, the function automatically initiates an update process.\n\nAdditionally, the optimizer argument is a crucial component for formulating and solving the optimization problem. Typically, using the GLPK or HiGHS solver is sufficient. For more detailed information, please refer to the JuMP documenatation.\n\nKeyword\n\nThe bridge keyword enables users to manage the bridging mechanism within the JuMP package.\n\nReturns\n\nThe function returns an instance of the PlacementPMU type, containing variables such as:\n\nbus: Bus labels with indices marking the positions of PMUs at buses.\nfrom: Branch labels with indices marking the positions of PMUs at from-bus ends.\nto: Branch labels with indices marking the positions of PMUs at to-bus ends.\n\nNote that if the conventional understanding of a PMU involves a device measuring the bus voltage phasor and all branch current phasors incident to the bus, the result is saved only in the bus variable. However, if we consider that a PMU measures individual phasors, each described with magnitude and angle, then measurements are needed at each bus in the bus variable, and each branch with positions given according to from and to variables.\n\nExample\n\nusing GLPK, Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\ncurrent!(system, analysis)\n\nplacement = pmuPlacement(system, GLPK.Optimizer)\n\n@pmu(label = \"PMU ?: !\")\nfor (bus, i) in placement.bus\n Vi, θi = analysis.voltage.magnitude[i], analysis.voltage.angle[i]\n addPmu!(system, device; bus = bus, magnitude = Vi, angle = θi)\nend\nfor branch in keys(placement.from)\n Iij, ψij = fromCurrent(system, analysis; label = branch)\n addPmu!(system, device; from = branch, magnitude = Iij, angle = ψij)\nend\nfor branch in keys(placement.to)\n Iji, ψji = toCurrent(system, analysis; label = branch)\n addPmu!(system, device; to = branch, magnitude = Iji, angle = ψji)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.pmuStateEstimation","page":"State Estimation","title":"JuliaGrid.pmuStateEstimation","text":"pmuStateEstimation(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function establishes the linear WLS model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the PMU state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device)\n\nSet up the PMU state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.pmuLavStateEstimation","page":"State Estimation","title":"JuliaGrid.pmuLavStateEstimation","text":"pmuLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function establishes the LAV model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, PMUStateEstimation{LinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::PMUStateEstimation)\n\nBy computing the bus voltage magnitudes and angles, the function solves the PMU state estimation model.\n\nUpdates\n\nThe resulting bus voltage magnitudes and angles are stored in the voltage field of the PMUStateEstimation type.\n\nExamples\n\nSolving the PMU state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\n\nSolving the PMU state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#DC-State-Estimation-2","page":"State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"dcStateEstimation\ndcLavStateEstimation\nsolve!(::PowerSystem, ::DCStateEstimation{LinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.dcStateEstimation","page":"State Estimation","title":"JuliaGrid.dcStateEstimation","text":"dcStateEstimation(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function establishes the WLS model for DC state estimation, where the vector of state variables contains only bus voltage angles.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the DC state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\n\nSet up the DC state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.dcLavStateEstimation","page":"State Estimation","title":"JuliaGrid.dcLavStateEstimation","text":"dcLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function establishes the LAV model for DC state estimation, where the vector of state variables contains only bus voltage angles.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, DCStateEstimation{LinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCStateEstimation)\n\nBy computing the bus voltage angles, the function solves the DC state estimation model.\n\nUpdates\n\nThe resulting bus voltage angles are stored in the voltage field of the DCStateEstimation type.\n\nExamples\n\nSolving the DC state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\n\nSolving the DC state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Bad-Data-Analysis-2","page":"State Estimation","title":"Bad Data Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"residualTest!","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.residualTest!","page":"State Estimation","title":"JuliaGrid.residualTest!","text":"residualTest!(system::PowerSystem, device::Measurement, analysis::StateEstimation;\n threshold)\n\nThe function conducts bad data detection and identification using the largest normalized residual test, subsequently removing measurement outliers from the measurement set. It can be executed after obtaining WLS estimator.\n\nArguments\n\nThis function requires the types PowerSystem, Measurement, and StateEstimation. The abstract type StateEstimation can have the following subtypes:\n\nACStateEstimation: Conducts bad data analysis within AC state estimation.\nPMUStateEstimation: Conducts bad data analysis within PMU state estimation.\nDCStateEstimation: Conducts bad data analysis within DC state estimation.\n\nKeyword\n\nThe keyword threshold establishes the identification threshold. If the largest normalized residual surpasses this threshold, the measurement is flagged as bad data. The default threshold value is set to threshold = 3.0.\n\nUpdates\n\nIf bad data is detected, the function flags the corresponding measurement within the Measurement type as out-of-service.\n\nMoreover, for DCStateEstimation and PMUStateEstimation types, the function removes the corresponding measurement from the coefficient matrix and mean vector. This facilitates direct progress to the function that solves the state estimation problem.\n\nReturns\n\nThe function returns an instance of the BadData type, which includes:\n\ndetect: Returns true after the function's execution if bad data is detected.\nmaxNormalizedResidual: Denotes the value of the largest normalized residual.\nlabel: Signifies the label of the bad data.\nindex: Represents the index of the bad data.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\n\noutlier = residualTest!(system, device, analysis; threshold = 4.0)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"function"}] +[{"location":"#JuliaGrid","page":"Introduction","title":"JuliaGrid","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid is a fast, flexible, and easy-to-use open-source tool for analyzing and modifying power system configurations and measurement data. It represents a comprehensive framework for steady-state power system analysis written in the Julia programming language. The framework is available as a Julia package under MIT License. JuliaGrid is primarily designed for researchers and academics, providing various state-of-the-art algorithms.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The framework's architecture centres around code-reusability paradigm, allowing users a high level of customization for their experiments. To simplify, the overall logic for setting the experiments and its analysis can be as follows:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Users define a power system with/without measurement data.\nUsers select between the AC or DC model.\nUsers define the specific type of required analysis.\nFinally, they solve the generated power system model.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Installation-Guide","page":"Introduction","title":"Installation Guide","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid is compatible with Julia version 1.9 and later. To get started with JuliaGrid, users should first install Julia and consider using a code editor for a smoother coding experience. For detailed instructions, please consult the Installation Guide.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To get the JuliaGrid package installed, execute the following Julia command:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"import Pkg\nPkg.add(\"JuliaGrid\")","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Documentation-Structure","page":"Introduction","title":"Documentation Structure","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"JuliaGrid documentation consists of three main parts:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The manual provides users with guidance on how to use available functions, its return values, and offers instructions for modifying power system configurations, measurement data, and other user specific analysis.\nThe tutorials delve deeper into the theoretical underpinnings of state-of-the-art algorithms, allowing users to gain an in-depth understanding of the equations used in various functions.\nAPI references offer a comprehensive list of objects, functions and methods within the package, categorised according to specific use-cases.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Getting-Started","page":"Introduction","title":"Getting Started","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Below, we have provided a list of exhaustive examples in order to ease users in getting started with the JuliaGrid package. These examples highlight some of the functionalities that the framework offers.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-Power-Flow","page":"Introduction","title":"AC Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = newtonRaphson(system) # Build the power flow model\nfor iteration = 1:10 # Begin the iteration loop\n stopping = mismatch!(system, analysis) # Compute power mismatches\n if all(stopping .< 1e-8) # Check if the stopping criterion is met\n println(\"Solution Found.\") # Output message indicating convergence\n break # Stop iterations if the criterion is met\n end\n solve!(system, analysis) # Compute voltage magnitudes and angles\nend\npower!(system, analysis) # Compute powers within the power system\ncurrent!(system, analysis) # Compute currents within the power system\n\nprintBusData(system, analysis) # Print data related to buses","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-Power-Flow","page":"Introduction","title":"DC Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\n@power(MW, MVAr, MVA) # Specify the power units for input data\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcPowerFlow(system) # Build the power flow analysis\nsolve!(system, analysis) # Compute voltage angles\n\n@generator(active = 20) # Define the template for generators\naddGenerator!(system, analysis; bus = 1) # Add the new generator to the power system\nsolve!(system, analysis) # Recompute voltage angles with the updated model\n\nprintBusSummary(system, analysis) # Print a summary of data related to buses","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-Optimal-Power-Flow","page":"Introduction","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid, Ipopt\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer) # Build the optimal power flow model\nsolve!(system, analysis) # Compute generator powers and bus voltages\ncurrent!(system, analysis) # Compute currents within the power system\n\n@branch(resistance = 0.01, reactance = 0.2) # Define the new template for branches\naddBranch!(system, analysis; from = 1, to = 5) # Add the new branch to the power system\nsolve!(system, analysis) # Recompute solutions with the updated model","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-Optimal-Power-Flow","page":"Introduction","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid, HiGHS\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer) # Build the optimal power flow model\nsolve!(system, analysis) # Compute generator powers and bus voltages\npower!(system, analysis) # Compute active powers within the power system\n\nprintBranchData(system, analysis) # Print data related to branches","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#AC-State-Estimation","page":"Introduction","title":"AC State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = gaussNewton(system, device) # Build the state estimation model\nfor iteration = 1:20 # Begin the iteration loop\n stopping = solve!(system, analysis) # Compute estimate of voltages\n if stopping < 1e-8 # Check if the stopping criterion is met\n println(\"Solution Found.\") # Output message indicating convergence\n break # Stop iterations if the criterion is met\n end\nend\npower!(system, analysis) # Compute active powers within the power system\n\nprintWattmeterData(system, device, analysis) # Print data related to wattmeters","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#PMU-State-Estimation","page":"Introduction","title":"PMU State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\nacModel!(system) # Create matrices and vectors for the AC model\n\nanalysis = pmuStateEstimation(system, device) # Build the state estimation model\nsolve!(system, analysis) # Compute estimate of voltages\n\nupdatePmu!(system, device, analysis; label = \"To 1\", angle = 0.0) # Update phasor measurement\nsolve!(system, analysis) # Recompute the solution with the updated model\n\nprintPmuData(system, device, analysis) # Print data related to PMUs","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#DC-State-Estimation","page":"Introduction","title":"DC State Estimation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"using JuliaGrid\n\nsystem = powerSystem(\"case14.h5\") # Build the power system model\ndevice = measurement(\"measurement14.h5\") # Build the measurement model\ndcModel!(system) # Create matrices and vectors for the DC model\n\nanalysis = dcStateEstimation(system, device) # Build the state estimation model\nsolve!(system, analysis) # Compute estimate of voltage angles\n\nresidualTest!(system, device, analysis) # Perform bad data analysis and remove outlier\nsolve!(system, analysis) # Recompute voltage angles with the updated model","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"","category":"page"},{"location":"#Contributors","page":"Introduction","title":"Contributors","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"Ognjen Kundacina - The Institute for Artificial Intelligence Research and Development of Serbia\nMuhamed Delalic - University of Sarajevo, Bosnia and Herzegovina\nArmin Teskeredzic - RWTH Aachen University, Germany\nMirsad Cosovic - University of Sarajevo, Bosnia and Herzegovina","category":"page"},{"location":"api/optimalPowerFlow/#OptimalPowerFlowAPI","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"For further information on this topic, please see the AC Optimal Power Flow or DC Optimal Power Flow sections of the Manual. Below, we have provided a list of functions that can be utilized for optimal power flow analysis.","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"To load optimal power flow API functionalities into the current scope, one can employ the following command:","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"using JuliaGrid, Ipopt, HiGHS","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#AC-Optimal-Power-Flow","page":"Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"acOptimalPowerFlow\nsolve!\nstartingPrimal!\nstartingDual!","category":"page"},{"location":"api/optimalPowerFlow/#DC-Optimal-Power-Flow","page":"Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"dcOptimalPowerFlow\nsolve!\nstartingPrimal!\nstartingDual!","category":"page"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#AC-Optimal-Power-Flow-2","page":"Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"acOptimalPowerFlow\nsolve!(::PowerSystem, ::ACOptimalPowerFlow)\nstartingPrimal!(::PowerSystem, ::ACOptimalPowerFlow)\nstartingDual!(::PowerSystem, ::ACOptimalPowerFlow)","category":"page"},{"location":"api/optimalPowerFlow/#JuliaGrid.acOptimalPowerFlow","page":"Optimal Power Flow","title":"JuliaGrid.acOptimalPowerFlow","text":"acOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name,\n magnitude, angle, active, reactive)\n\nThe function sets up the optimization model for solving the AC optimal power flow problem.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the AC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type.\n\nKeywords\n\nJuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:\n\nbridge: manage the bridging mechanism (default: false),\nname: manage the creation of string names (default: true).\n\nAdditionally, users can modify variable names used for printing and writing through the keywords magnitude, angle, active, and reactive. For instance, users can choose magnitude = \"V\" and angle = \"θ\" to display equations in a more readable format.\n\nReturns\n\nThe function returns an instance of the ACOptimalPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The JuMP model, references to the variables, constraints, and objective.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/optimalPowerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function solves the AC optimal power flow model, computing the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.\n\nUpdates\n\nThe calculated active and reactive powers, as well as voltage magnitudes and angles, are stored in the power.generator and voltage fields of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingPrimal!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingPrimal!","text":"startingPrimal!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function retrieves the active and reactive power outputs of the generators, as well as the voltage magnitudes and angles from the PowerSystem composite type. It then assigns these values to the ACOptimalPowerFlow type, allowing users to initialize starting primal values as needed.\n\nUpdates\n\nThis function only updates the voltage and generator fields of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingPrimal!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingDual!-Tuple{PowerSystem, ACOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingDual!","text":"startingDual!(system::PowerSystem, analysis::ACOptimalPowerFlow)\n\nThe function removes all values of the dual variables.\n\nUpdates\n\nThis function only updates the dual field of the ACOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingDual!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"","category":"page"},{"location":"api/optimalPowerFlow/#DC-Optimal-Power-Flow-2","page":"Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"api/optimalPowerFlow/","page":"Optimal Power Flow","title":"Optimal Power Flow","text":"dcOptimalPowerFlow\nsolve!(::PowerSystem, ::DCOptimalPowerFlow)\nstartingPrimal!(::PowerSystem, ::DCOptimalPowerFlow)\nstartingDual!(::PowerSystem, ::DCOptimalPowerFlow)","category":"page"},{"location":"api/optimalPowerFlow/#JuliaGrid.dcOptimalPowerFlow","page":"Optimal Power Flow","title":"JuliaGrid.dcOptimalPowerFlow","text":"dcOptimalPowerFlow(system::PowerSystem, optimizer; bridge, name, angle, active)\n\nThe function sets up the optimization model for solving the DC optimal power flow problem.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the optimizer argument is also required to create and solve the optimization problem. Specifically, JuliaGrid constructs the DC optimal power flow using the JuMP package and provides support for commonly employed solvers. For more detailed information, please consult the JuMP documentation.\n\nUpdates\n\nIf the DC model has not been created, the function automatically initiates an update within the dc field of the PowerSystem type.\n\nKeywords\n\nJuliaGrid offers the ability to manipulate the jump model based on the guidelines provided in the JuMP documentation. However, certain configurations may require different method calls, such as:\n\nbridge: manage the bridging mechanism (default: false),\nname: manage the creation of string names (default: true).\n\nAdditionally, users can modify variable names used for printing and writing through the keywords angle and active. For instance, users can choose angle = \"θ\" to display equations in a more readable format.\n\nReturns\n\nThe function returns an instance of the DCOptimalPowerFlow type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angle,\npower: The variable allocated to store the active powers,\nmethod: The JuMP model, references to the variables, constraints, and objective.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/optimalPowerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function solves the DC optimal power flow model, computing the active power outputs of the generators, as well as the bus voltage angles.\n\nUpdates\n\nThe calculated active powers, as well as voltage angles, are stored in the power.generator and voltage fields of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingPrimal!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingPrimal!","text":"startingPrimal!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function retrieves the active power outputs of the generators and the bus voltage angles from the PowerSystem composite type. These values are then assigned to the DCOptimalPowerFlow type, enabling users to initialize starting primal values according to their requirements.\n\nUpdates\n\nThis function only updates the voltage and generator fields of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)\n\nstartingPrimal!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/optimalPowerFlow/#JuliaGrid.startingDual!-Tuple{PowerSystem, DCOptimalPowerFlow}","page":"Optimal Power Flow","title":"JuliaGrid.startingDual!","text":"startingDual!(system::PowerSystem, analysis::DCOptimalPowerFlow)\n\nThe function removes all values of the dual variables.\n\nUpdates\n\nThis function only updates the dual field of the DCOptimalPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = 14, active = 0.1, angle = -0.17)\n\nstartingDual!(system, analysis)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"manual/acPowerFlow/#ACPowerFlowManual","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To perform the AC power flow analysis, we will first need the PowerSystem type that has been created with the AC model. Following that, we can construct the power flow model encapsulated within the ACPowerFlow type by employing one of the following functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"newtonRaphson,\nfastNewtonRaphsonBX,\nfastNewtonRaphsonXB,\ngaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These functions will set up the AC power flow framework. To obtain bus voltages and solve the power flow problem, we can use the following functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"mismatch!,\nsolve!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, the package provides two functions for reactive power limit validation of generators and adjusting the voltage angles to match an arbitrary bus angle:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"reactiveLimit!,\nadjustAngle!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the AC power flow solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses, branches, or generators:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses, branches, or generators.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#BusTypeModificationManual","page":"AC Power Flow","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Depending on how the system is constructed, the types of buses that are initially set are checked and can be changed during the construction of the ACPowerFlow type.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Assuming the Newton-Raphson method has been chosen, to explain the details, we can observe a power system:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddGenerator!(system; bus = \"Bus 2\")\n\nanalysis = newtonRaphson(system)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Initially, Bus 1 is set as the slack bus (type = 3), and Bus 2 and Bus 3 are generator buses (type = 2). However, Bus 3 does not have a generator, and JuliaGrid considers this a mistake and changes the corresponding bus to a demand bus (type = 1).","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After this step, JuliaGrid verifies the slack bus. Initially, the slack bus (type = 3) corresponds to Bus 1, but since it does not have an in-service generator connected to it, JuliaGrid recognizes it as another mistake. Therefore, JuliaGrid assigns a new slack bus from the available generator buses (type = 2) that have connected in-service generators. In this specific example, Bus 2 becomes the new slack bus.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid\n@default(unit)\n@default(template)\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddGenerator!(system; bus = \"Bus 2\")\n\nacModel!(system)\nanalysis = newtonRaphson(system)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As a result, we can observe the updated array of bus types:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Note that, if a bus is initially defined as the demand bus (type = 1) and later a generator is added to it, the bus type will not be changed to the generator bus (type = 2). Instead, it will remain as a demand bus.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nOnly the type of these buses that are defined as generator buses (type = 2) but do not have a connected in-service generator will be changed to demand buses (type = 1).The bus that is defined as the slack bus (type = 3) but lacks a connected in-service generator will have its type changed to the demand bus (type = 1). Meanwhile, the first generator bus (type = 2) with an in-service generator connected to it will be assigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#SetupStartingVoltagesManual","page":"AC Power Flow","title":"Setup Starting Voltages","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To begin analyzing the AC power flow in JuliaGrid, we must first establish the PowerSystem type. Once the power system is set up, we can select one of the available methods for solving the AC power flow problem, such as newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Assuming we have selected the Newton-Raphson method, we can use the following code snippet:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.0, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, magnitude = 0.9, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 2, magnitude = 0.8, angle = -0.2)\n\naddGenerator!(system; bus = \"Bus 1\", magnitude = 1.3)\naddGenerator!(system; bus = \"Bus 2\", magnitude = 1.1)\naddGenerator!(system; bus = \"Bus 3\", magnitude = 1.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, the function newtonRaphson generates starting voltage vectors in polar coordinates.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage magnitudes are set to:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This vector is created based on the bus types by selecting voltage magnitude values from the PowerSystem type, using the vectors:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"[system.bus.voltage.magnitude system.generator.voltage.magnitude]","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage angles are set to:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This vector is derived from the voltage angle values in the PowerSystem type:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system.bus.voltage.angle","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe rule governing the specification of starting voltage magnitudes is simple. If a bus has an in-service generator and is declared the generator bus (type = 2), then the starting voltage magnitudes are specified using the setpoint provided within the generator. This is because the generator bus has known values of voltage magnitude that are specified within the generator.On the other hand, the slack bus (type = 3) always requires an in-service generator. The starting value of the voltage magnitude at the slack bus is determined exclusively by the setpoints provided within the generators connected to it. This is a result of the slack bus having a known voltage magnitude that must be maintained.If there are multiple generators connected to the generator or slack bus, the initial voltage magnitude will align with the magnitude setpoint specified for the first in-service generator in the list.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Custom-Starting-Voltages","page":"AC Power Flow","title":"Custom Starting Voltages","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This method of specifying starting values has a significant advantage in that it allows the user to easily change the starting voltage magnitudes and angles, which play a crucial role in iterative methods. For instance, suppose we define our power system as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.0, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, magnitude = 0.9, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 2, magnitude = 0.8, angle = -0.2)\n\naddGenerator!(system; bus = \"Bus 1\", magnitude = 1.1)\naddGenerator!(system; bus = \"Bus 3\", magnitude = 1.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, the user can initiate a \"flat start\", this can be easily done as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for i = 1:system.bus.number\n system.bus.voltage.magnitude[i] = 1.0\n system.bus.voltage.angle[i] = 0.0\nend\n\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The starting voltage values are:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Consequently, the iteration begins with a fixed set of voltage magnitude values that remain constant throughout the iteration process. The remaining values are initialized as part of the \"flat start\" approach.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerFlowSolutionManual","page":"AC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To start, we will create a power system and define the AC model by invoking the acModel! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\n\n@generator(active = 3.2)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", magnitude = 1.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the AC model is defined, we can choose the method to solve the power flow problem. JuliaGrid provides four methods: newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, and gaussSeidel.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For example, to use the Newton-Raphson method to solve the power flow problem, we can use:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, the user activates LU factorization to solve the system of linear equations within each iteration of the Newton-Raphson method. However, users can specifically opt for the QR factorization method:analysis = newtonRaphson(system, QR)The capability to change the factorization method is exclusively available for the Newton-Raphson and fast Newton-Raphson methods.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This function sets up the desired method for an iterative process based on two functions: mismatch! and solve!. The mismatch! function calculates the active and reactive power injection mismatches using the given voltage magnitudes and angles, while solve! computes the voltage magnitudes and angles.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To perform an iterative process with the Newton-Raphson or fast Newton-Raphson methods in JuliaGrid, the mismatch! function must be included inside the iteration loop. For instance:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Upon completion of the AC power flow analysis, the solution is conveyed through the bus voltage magnitudes and angles. Here are the values corresponding to the buses:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In contrast, the iterative loop of the Gauss-Seidel method does not require the mismatch! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = gaussSeidel(system)\nfor iteration = 1:100\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In these examples, the algorithms run until the specified number of iterations is reached.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nWe recommend that the reader refer to the tutorial on AC Power Flow Analysis, where we explain the implementation of the methods and algorithm structures in detail.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Breaking-the-Iterative-Process","page":"AC Power Flow","title":"Breaking the Iterative Process","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can terminate the iterative process using the mismatch! function. The following code shows an example of how to use the function to break out of the iteration loop:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, rad, V) # hide\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n println(\"Solution Found.\")\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The mismatch! function returns the maximum absolute values of active and reactive power injection mismatches, which are commonly used as a convergence criterion in iterative AC power flow algorithms. Note that the function can also be used to terminate the loop when using the Gauss-Seidel method, even though it is not required.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nTo ensure an accurate count of iterations, the user should place the iteration counter after the condition expressions within the if construct.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Combining-Methods","page":"AC Power Flow","title":"Combining Methods","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The PowerSystem type, once created, can be shared among different methods, offering several advantages.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For instance, while the Gauss-Seidel method is commonly used to swiftly derive an approximate solution, the Newton-Raphson method is favored for obtaining precise final solutions. Hence, a strategy involves employing the Gauss-Seidel method for a limited number of iterations, followed by initializing the Newton-Raphson method with the voltages obtained from the Gauss-Seidel method, leveraging it as a starting point for further refinement:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"gs = gaussSeidel(system)\nfor iteration = 1:5\n solve!(system, gs)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, we can initialize the Newton-Raphson method with the voltages obtained from the Gauss-Seidel method and start the algorithm from that point:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = gs.voltage.magnitude[i]\n analysis.voltage.angle[i] = gs.voltage.angle[i]\nend\n\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe functions newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel only modify the PowerSystem type to eliminate mistakes in the bus types as explained in the section Bus Type Modification. Further, the functions mismatch! and solve! do not modify the PowerSystem type at all. Therefore, it is safe to use the same PowerSystem type for multiple analyses once it has been created.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Print-Results-in-the-REPL","page":"AC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Save-Results-to-a-File","page":"AC Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Save-Results-to-a-CSV-File","page":"AC Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusData(system, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerSystemAlterationManual","page":"AC Power Flow","title":"Power System Update","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After establishing the PowerSystem type using the powerSystem function and configuring the AC model with acModel!, users gain the capability to incorporate new branches and generators. Furthermore, they can adjust buses, branches, and generators.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once updates are done, users can progress towards generating the ACPowerFlow type using the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function. Ultimately, resolving the AC power flow is achieved through the utilization of the mismatch! and solve! functions:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1, active = 3.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the defined power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\n\nupdateBus!(system; label = \"Bus 2\", active = 0.2)\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system; label = \"Branch 1\", status = 0)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nupdateGenerator!(system; label = \"Generator 1\", active = 0.3)\n\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the updated power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate the PowerSystem within the ac field from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerFlowUpdateManual","page":"AC Power Flow","title":"Power Flow Update","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"An advanced methodology involves users establishing the ACPowerFlow type using newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel just once. After this initial setup, users can integrate new branches and generators, and also have the capability to modify buses, branches, and generators, all without the need to recreate the ACPowerFlow type.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This advancement extends beyond the previous scenario where recreating the PowerSystem and AC model was unnecessary, to now include the scenario where ACPowerFlow also does not need to be recreated. Such efficiency proves particularly beneficial in cases where JuliaGrid can reuse established Jacobian matrices or even factorizations, especially when users choose the fast Newton-Raphson method.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"By modifying the previous example, we observe that we now create the ACPowerFlow type only once using the newtonRaphson function. This approach allows us to circumvent the need for reinitializing the Jacobian matrix, enabling us to proceed directly with iterations:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", magnitude = 1.1, active = 3.2)\n\nacModel!(system)\nanalysis = newtonRaphson(system) # <- Build ACPowerFlow for the defined power system\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\n\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.2)\n\naddBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system, analysis; label = \"Branch 1\", status = 0)\n\naddGenerator!(system, analysis; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 0.3)\n\n# <- No need for re-build; we have already updated the existing ACPowerFlow instance\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate both the PowerSystem within the ac field and the ACPowerFlow from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Fast-Newton-Raphson:-Reusing-Jacobian-Matrices-Factorizations","page":"AC Power Flow","title":"Fast Newton-Raphson: Reusing Jacobian Matrices Factorizations","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"An intriguing scenario unfolds when employing the fast Newton-Raphson method. Continuing from the previous example, let us now initialize the fast Newton-Raphson method and proceed with iterations as outlined below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = fastNewtonRaphsonBX(system)\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Throughout this process, JuliaGrid will factorize the constant Jacobian matrices that govern the fast Newton-Raphson method.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, let us make changes to the power system and proceed directly to the iteration step:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", reactive = 0.02)\nupdateGenerator!(system, analysis; label = \"Generator 1\", reactive = 0.1)\n\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nIn this scenario, JuliaGrid identifies cases where the user has not altered parameters that impact the Jacobian matrices. Consequently, JuliaGrid efficiently utilizes the previously performed factorizations, leading to a notably faster solution compared to recomputing the factorization process.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Warm-Start","page":"AC Power Flow","title":"Warm Start","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In these scenarios, users leverage the previously created PowerSystem type with the AC model and also reuse the ACPowerFlow type, proceeding directly to the iterations. This approach offers the advantage of a \"warm start\", wherein the initial voltages for the subsequent iteration step align with the solution from the previous iteration step. This alignment facilitates an efficient continuation of the power flow analysis.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Let us now make another alteration to the power system:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", active = 0.1, magnitude = 0.95, angle = -0.07)\nupdateGenerator!(system, analysis; label = \"Generator 2\", reactive = 0.2, magnitude = 1.1)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"With these modifications we are not only altering the power system, but also starting voltages. For the next uses of one of the methods, these values now are:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Therefore, users possess the flexibility to adjust these initial values as needed by employing the magnitude and angle keywords within the updateBus! and updateGenerator! functions.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"If users prefer to set starting voltages according to the typical scenario, they can accomplish this through the startingVoltage! function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"startingVoltage!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Now, we have starting voltages defined exclusively according to the PowerSystem. These values are exactly the same as if we executed the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function after all the updates we performed:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Limitations","page":"AC Power Flow","title":"Limitations","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function oversees bus type validations, as outlined in the Bus Type Modification section. Consequently, attempting to change bus types or leaving generator buses without a generator and then proceeding directly to the iteration process is not viable.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In such scenarios, JuliaGrid will raise an error:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", type = 2)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In this scenario, the user must execute the newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, or gaussSeidel function instead of trying to reuse them, for example:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"updateBus!(system; label = \"Bus 2\", type = 2)\n\nanalysis = fastNewtonRaphsonBX(system)\nfor iteration = 1:100\n mismatch!(system, analysis)\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nAfter creating the PowerSystem and ACPowerFlow types, users can add or modify buses, branches, and generators before directly proceeding to iterations. JuliaGrid automatically executes the necessary functions when adjustments lead to a valid solution. However, if modifications are incompatible, like altering bus types, JuliaGrid raises an error to prevent misleading outcomes, ensuring accuracy.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#ACPowerCurrentAnalysisManual","page":"AC Power Flow","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the solution from the AC power flow, we can calculate various electrical quantities related to buses, branches, and generators using the power! and current! functions. For instance, let us consider the power system for which we obtained the AC power flow solution:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.6)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.1, susceptance = 0.03)\naddBus!(system; label = \"Bus 3\", type = 1, conductance = 0.02)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.4)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.0, reactive = 0.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"For instance, if we want to show the active power injections and the to-bus current angles, we can employ the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.to.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nTo better understand the powers and currents associated with buses, branches, and generators that are obtained by the power! and current! functions, we suggest referring to the tutorials on AC Power Flow Analysis.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Print-Results-in-the-REPL-2","page":"AC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus summary with the desired units, users can use the following function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nprintBusSummary(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Injection","page":"AC Power Flow","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC Power Flow","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC Power Flow","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 3\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-Flow","page":"AC Power Flow","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the functions provided below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC Power Flow","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC Power Flow","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Generator-Active-and-Reactive-Power-Output","page":"AC Power Flow","title":"Generator Active and Reactive Power Output","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can compute the active and reactive power output of a particular generator using the function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"active, reactive = generatorPower(system, analysis; label = \"Generator 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Injection","page":"AC Power Flow","title":"Current Injection","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Flow","page":"AC Power Flow","title":"Current Flow","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#Current-Through-Series-Impedance","page":"AC Power Flow","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#GeneratorReactivePowerLimitsManual","page":"AC Power Flow","title":"Generator Reactive Power Limits","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function reactiveLimit! can be used to check if the generators' output of reactive power is within the defined limits after obtaining the solution from the AC power flow analysis:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\naddBus!(system; label = \"Bus 3\", type = 2, reactive = 0.05)\naddBus!(system; label = \"Bus 4\", type = 2, reactive = 0.05)\n\n@branch(resistance = 0.015)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 4\", reactance = 0.004)\n\n@generator(minReactive = -0.4, maxReactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\")\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", reactive = 0.8)\naddGenerator!(system; label = \"Generator 3\", bus = \"Bus 4\", reactive = 0.9)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nviolate = reactiveLimit!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The output reactive power of the observed generators is subject to limits which are defined as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"[system.generator.capability.minReactive system.generator.capability.maxReactive]","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After obtaining the solution of the AC power flow analysis, the reactiveLimit! function is used to internally calculate the output powers of the generators and verify if these values exceed the defined limits. Consequently, the variable violate indicates whether there is a violation of limits.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In the provided example, it can be observed that the Generator 2 and Generator 3 violate the maximum limit:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.generator.label, violate)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Due to these violations of limits, the PowerSystem type undergoes modifications, and the output reactive power at the limit-violating generators is adjusted as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.generator.label, system.generator.output.reactive)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To ensure that these values stay within the limits, the bus type must be changed from the generator bus (type = 2) to the demand bus (type = 1), as shown below:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After modifying the PowerSystem type as described earlier, we can run the simulation again with the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the simulation is complete, we can verify that all generator reactive power outputs now satisfy the limits by checking the violate variable again:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"violate = reactiveLimit!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nThe reactiveLimit! function changes the PowerSystem type deliberately because it is intended to help users create the power system where all reactive power outputs of the generators are within limits.","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"manual/acPowerFlow/#New-Slack-Bus","page":"AC Power Flow","title":"New Slack Bus","text":"","category":"section"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Looking at the following code example, we can see that the output limits of the generator are set only for Generator 1 that is connected to the slack bus:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, reactive = 0.05)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\naddBus!(system; label = \"Bus 3\", type = 2)\naddBus!(system; label = \"Bus 4\", type = 2)\n\n@branch(resistance = 0.01)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 4\", reactance = 0.004)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", maxReactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 4\", reactive = 0.3)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Upon checking the limits, we can observe that the slack bus has been transformed by executing the following code:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"violate = reactiveLimit!(system, analysis)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, the generator connected to the slack bus is violating the minimum reactive power limit, which indicates the need to convert the slack bus. It is important to note that the new slack bus can be created only from the generator bus (type = 2). We will now perform another AC power flow analysis on the modified system using the following:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"analysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After examining the bus voltages, we will focus on the angles:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We can observe that the angles have been calculated based on the new slack bus. JuliaGrid offers the function to adjust these angles to match the original slack bus as follows:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"adjustAngle!(system, analysis; slack = \"Bus 1\")","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After executing the above code, the updated results can be viewed:","category":"page"},{"location":"manual/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/#ACStateEstimationManual","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To perform nonlinear or AC state estimation, the initial requirement is to have the PowerSystem type configured with the AC model, along with the Measurement type storing measurement data. Next, we can develop either the weighted least-squares (WLS) model, utilizing the Gauss-Newton method, or the least absolute value (LAV) model. These models are encapsulated within the ACStateEstimation type:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"gaussNewton,\nacLavStateEstimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For resolving the AC state estimation problem and obtaining bus voltage magnitudes and angles, utilize the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"solve!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After executing the function solve!, where the user employs the Gauss-Newton method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Moreover, before the creating ACStateEstimation type, users can initiate observability analysis to identify observable islands and restore observability by employing:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islandTopologicalFlow,\nislandTopological,\nrestorationGram!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After obtaining the AC state estimation solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses and branches:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses or branches.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEBusTypeModificationManual","page":"AC State Estimation","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In AC state estimation, it is necessary to designate a slack bus, where the bus voltage angle is known. Therefore, when establishing the ACStateEstimation type, the initially assigned slack bus is evaluated and may be altered. If the designated slack bus (type = 3) lacks a connected in-service generator, it will be changed to a demand bus (type = 1). Conversely, the first generator bus (type = 2) with an active in-service generator linked to it will be reassigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEObservabilityAnalysisManual","page":"AC State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To initiate the power system with measurements at specific locations, follow the provided example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.5, reactive = 0.01)\naddBus!(system; label = \"Bus 4\", type = 1, active = 0.2, reactive = 0.02)\naddBus!(system; label = \"Bus 5\", type = 1, active = 0.3, reactive = 0.03)\naddBus!(system; label = \"Bus 6\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 7\", type = 1, active = 0.1, reactive = 0.01)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.002)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 5\", reactance = 0.02)\naddBranch!(system; label = \"Branch 4\", from = \"Bus 3\", to = \"Bus 4\", reactance = 0.03)\naddBranch!(system; label = \"Branch 5\", from = \"Bus 5\", to = \"Bus 6\", reactance = 0.05)\naddBranch!(system; label = \"Branch 6\", from = \"Bus 3\", to = \"Bus 5\", reactance = 0.05)\naddBranch!(system; label = \"Branch 7\", from = \"Bus 6\", to = \"Bus 7\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 4.2, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", active = 0.2, reactive = 0.1)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 1.15)\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = -0.50)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 4\", active = 0.20)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 4\", reactive = -0.02)\n\naddWattmeter!(system, device; label = \"Wattmeter 3\", from = \"Branch 5\", active = -0.20)\naddVarmeter!(system, device; label = \"Varmeter 3\", from = \"Branch 5\", reactive = 0.02)\n\naddWattmeter!(system, device; label = \"Wattmeter 4\", bus = \"Bus 2\", active = -0.1)\naddVarmeter!(system, device; label = \"Varmeter 4\", bus = \"Bus 2\", reactive = -0.01)\n\naddWattmeter!(system, device; label = \"Wattmeter 5\", bus = \"Bus 3\", active = -0.30)\naddVarmeter!(system, device; label = \"Varmeter 5\", bus = \"Bus 3\", reactive = 0.66)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Attempting to solve this system immediately may not be possible because the gain matrix will be singular. To avoid this situation, users can perform observability analysis.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid employs standard observability analysis performed on the linear decoupled measurement model. Active power measurements from wattmeters are utilized to estimate bus voltage angles, while reactive power measurements from varmeters are used to estimate bus voltage magnitudes. This necessitates that measurements of active and reactive power come in pairs.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Observability Analysis for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"However, the initial step involves defining observable islands. JuliaGrid offers users two options for obtaining observable islands: flow observable islands or maximal observable islands. The selection depends on the power system's structure and available measurements. Identifying only flow observable islands reduces complexity in the island detection function, but increases complexity in the restoration function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Flow-Observable-Islands","page":"AC State Estimation","title":"Flow Observable Islands","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, let us identify flow observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopologicalFlow(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, four flow observable islands are identified: Bus 1 and Bus 2 form the first island, Bus 3 and Bus 4 form the second island, Bus 5 and Bus 6 constitute the third island, while Bus 7 forms the fourth island:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Maximal-Observable-Islands","page":"AC State Estimation","title":"Maximal Observable Islands","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we will instruct the user on obtaining maximal observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome reveals the identification of two maximal observable islands:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is evident that upon comparing this result with the flow islands, the merging of the two injection measurements at Bus 2 and Bus 3 consolidated the first, second, and third flow observable islands into a single island.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Restore-Observability","page":"AC State Estimation","title":"Restore Observability","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Before commencing the restoration of observability in the context of the linear decoupled measurement model and observability analysis, it is imperative to ensure that the system possesses one bus voltage magnitude measurement. This necessity arises from the fact that observable islands are identified based on wattmeters, where wattmeters are tasked with estimating voltage angles. Since one voltage angle is already known from the slack bus, the same principle should be applied to bus voltage magnitudes. Therefore, to address this requirement, we add:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user needs to establish a set of pseudo-measurements, where measurements must come in pairs as well. Let us create that set:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"pseudo = measurement()\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 1\", bus = \"Bus 1\", active = 0.31)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 1\", bus = \"Bus 1\", reactive = -0.19)\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 2\", from = \"Branch 7\", active = 0.10)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 2\", from = \"Branch 7\", reactive = 0.01)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThe labels for specific pseudo-measurements must differ from those defined in the measurements stored in the device set. This is necessary because the next step involves adding pseudo-measurements to the device set.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user can execute the restorationGram! function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"restorationGram!(system, device, pseudo, islands)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This function attempts to restore observability using pseudo-measurements. As a result, the inclusion of measurements from Pseudo-Wattmeter 2 and Pseudo-Varmeter 2 facilitates observability restoration, and these measurements are subsequently added to the device variable:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device.wattmeter.label\ndevice.varmeter.label\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, the power system becomes observable, allowing the user to proceed with forming the AC state estimation model and solving it. Ensuring the observability of the system does not guarantee obtaining accurate estimates of the state variables. Numerical ill-conditioning may adversely impact the state estimation algorithm. However, in most cases, efficient estimation becomes feasible when the system is observable [2].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, it is worth mentioning that restoration might encounter difficulties due to the default zero pivot threshold set at 1e-5. This threshold can be modified using the restorationGram! function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nDuring the restoration step, if users define bus phasor measurements, these measurements will be considered. Consequently, the system may achieve observability even if multiple islands persist.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACLSStateEstimationSolutionManual","page":"AC State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To begin, we will define the PowerSystem and Measurement types:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\")\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-2)\n\n@ammeter(label = \"Ammeter ? (!)\")\naddAmmeter!(system, device; from = \"Branch 3\", magnitude = 0.947, variance = 1e-1)\naddAmmeter!(system, device; to = \"Branch 2\", magnitude = 1.674, variance = 1e-1)\n\n@wattmeter(label = \"Wattmeter ? (!)\")\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1, variance = 2e-3)\n\n@varmeter(label = \"Varmeter ? (!)\")\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059, variance = 1e-4)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, to establish the AC state estimation model, we will utilize the gaussNewton function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the system of linear equations within each iteration of the Gauss-Newton method. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = gaussNewton(system, device, LDLt)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Setup-Starting-Voltages","page":"AC State Estimation","title":"Setup Starting Voltages","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The initial voltages for the Gauss-Newton method are determined based on the specified initial voltage magnitudes and angles within the buses of the PowerSystem type. These values are then forwarded to the ACStateEstimation during the execution of the gaussNewton function. Therefore, the starting voltages in this example are as follows:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the flexibility to modify these vectors according to their own requirements in order to adjust the starting voltages. For instance, users can conduct an initial AC power flow analysis and utilize the obtained solution as the starting voltages for AC state estimation:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"powerFlow = newtonRaphson(system)\nfor iteration = 1:10\n mismatch!(system, powerFlow)\n solve!(system, powerFlow)\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = powerFlow.voltage.magnitude[i]\n analysis.voltage.angle[i] = powerFlow.voltage.angle[i]\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#State-Estimator","page":"AC State Estimation","title":"State Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To conduct an iterative process using the Gauss-Newton method, it is essential to include the solve! function inside the iteration loop. For example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for iteration = 1:20\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once the state estimator is obtained, users can access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Breaking-the-Iterative-Process","page":"AC State Estimation","title":"Breaking the Iterative Process","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The iterative process can be terminated using the solve! function. The following code demonstrates how to utilize this function to break out of the iteration loop:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n println(\"Solution Found.\")\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The solve! function returns the maximum absolute values of the state variable increment, which are commonly used as a convergence criterion in the iterative Gauss-Newton algorithm.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on AC State Estimation for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Inclusion-of-PMUs-in-Rectangular-Coordinates","page":"AC State Estimation","title":"Inclusion of PMUs in Rectangular Coordinates","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the example above, our focus is solely on solving the AC state estimation using SCADA measurements. However, users have the option to also integrate PMUs into the AC state estimation, either in the rectangular or polar coordinate system.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The default approach is to include PMUs in the rectangular coordinate system:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; to = \"Branch 1\", magnitude = 1.05, angle = 3.047)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the case of the rectangular system, inclusion resolves ill-conditioned problems arising in polar coordinates due to small values of current magnitudes. However, this approach's main disadvantage is related to measurement errors, as measurement errors correspond to polar coordinates. Therefore, the covariance matrix must be transformed from polar to rectangular coordinates [3]. As a result, measurement errors of a single PMU are correlated, and the covariance matrix does not have a diagonal form. Despite that, the measurement error covariance matrix is usually considered as a diagonal matrix, affecting the accuracy of the state estimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the example above, we specifically include PMUs where measurement error correlations are disregarded. This is evident through the precision matrix, which maintains a diagonal form:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device);\nanalysis.method.precision","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Lastly, we incorporate correlation into our model by adding a new PMU with the desired error correlation:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 0.95, angle = -0.08, correlated = true)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, we can observe the precision matrix that does not hold a diagonal form:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device);\nanalysis.method.precision","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Inclusion-of-PMUs-in-Polar-Coordinates","page":"AC State Estimation","title":"Inclusion of PMUs in Polar Coordinates","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The second approach involves incorporating these measurements into the polar coordinate system. For instance:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; from = \"Branch 1\", magnitude = 1.048, angle = -0.057, polar = true)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This inclusion of PMUs provides more accurate state estimates compared to rectangular inclusion, but demands longer computing time. PMUs are handled in the same manner as SCADA measurements. However, this approach is susceptible to ill-conditioned problems arising in polar coordinates due to small values of current magnitudes [3, 4].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nIt is important to note that with each individual phasor measurement, we can set the coordinate system, providing flexibility to include some in polar and some in rectangular systems. This flexibility is particularly valuable because bus voltage phasor measurements are preferably included in a polar coordinate system, while current phasor measurements are best suited to a rectangular coordinate system.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Alternative-Formulation","page":"AC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device; label = \"PMU 2 (Bus 3)\", correlated = false)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, by specifying the Orthogonal argument in the gaussNewton function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device, Orthogonal)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Print-Results-in-the-REPL","page":"AC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Save-Results-to-a-File","page":"AC State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nWe also provide functions to print or save state estimation results, such as estimated values and residuals. For more details, users can consult the Power and Current Analysis section of this manual.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACBadDataDetectionManual","page":"AC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After acquiring the WLS solution using the Gauss-Newton method, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new measurement. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; from = \"Branch 2\", active = 31.1)\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we can observe the impact of the outlier on the solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the AC state estimation model:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective measurement as out-of-service within the Measurement type.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After removing bad data, a new estimate can be computed without considering this specific measurement. The user has the option to either restart the gaussNewton function or proceed directly to the iteration loop. However, if the latter option is chosen, using voltages obtained with outlier presence as the starting point could significantly impede algorithm convergence. To avoid this undesirable outcome, the user should first establish a new starting point and commence the iteration procedure. For instance:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for i = 1:system.bus.number\n analysis.voltage.magnitude[i] = system.bus.voltage.magnitude[i]\n analysis.voltage.angle[i] = system.bus.voltage.angle[i]\nend\n\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, we obtain a new solution devoid of the impact of the outlier measurement:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#PMULAVtateEstimationSolutionManual","page":"AC State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Setup-Starting-Primal-Values","page":"AC State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the ACStateEstimation type. By default, these values are initially established using the initial bus voltage magnitudes and angles from PowerSystem type:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Solution","page":"AC State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACMeasurementsAlterationManual","page":"AC State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the ACStateEstimation type using the gaussNewton or acLavStateEstimation function. Ultimately, resolving the AC state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\", variance = 1e-3)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\n\n@wattmeter(label = \"Wattmeter ? (!)\", varianceBus = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1)\n\n@varmeter(label = \"Varmeter ? (!)\", varianceFrom = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01)\n\n@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.976, angle = -0.052)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the defined model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924)\nupdateWattmeter!(system, device; label = \"Wattmeter 2 (Bus 2)\", variance = 1e-4)\n\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-5)\nupdateVarmeter!(system, device; label = \"Varmeter 2 (Bus 2)\", reactive = -0.011)\n\nupdatePmu!(system, device; label = \"PMU 1 (Bus 2)\", polar = false)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the updated model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACStateEstimationUpdateManual","page":"AC State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"An advanced methodology involves users establishing the ACStateEstimation type using gaussNewton or acLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the ACStateEstimation type.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where ACStateEstimation also does not need to be recreated.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of ACStateEstimation is not practical in terms of reusing this type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can modify the prior example to achieve the same model without establishing ACStateEstimation twice:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@voltmeter(label = \"Voltmeter ? (!)\", variance = 1e-3)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\n\n@wattmeter(label = \"Wattmeter ? (!)\", varianceBus = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1)\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924, status = 0)\n\n@varmeter(label = \"Varmeter ? (!)\", varianceFrom = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01)\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-5, status = 0)\n\n@pmu(label = \"PMU ? (!)\")\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.976, angle = -0.052)\n\nanalysis = gaussNewton(system, device) # <- Build ACStateEstimation for the defined model\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 3 (From Branch 3)\", status = 1)\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 2 (Bus 2)\", variance = 1e-4)\n\nupdateVarmeter!(system, device, analysis; label = \"Varmeter 3 (To Branch 3)\", status = 1)\nupdateVarmeter!(system, device, analysis; label = \"Varmeter 2 (Bus 2)\", reactive = -0.011)\n\nupdatePmu!(system, device, analysis; label = \"PMU 1 (Bus 2)\", polar = false)\n\n# <- No need for re-build; we have already updated the existing ACStateEstimation instance\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the ACStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#ACSEPowerCurrentAnalysisManual","page":"AC State Estimation","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After obtaining the solution from the AC state estimation, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the model for which we obtained the AC state estimation solution:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, susceptance = 0.002)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\naddWattmeter!(system, device; from = \"Branch 1\", active = 1.046, variance = 1e-2)\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.1, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 3\", active = 0.924, variance = 1e-3)\n\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.059, variance = 1e-3)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = -0.01, variance = 1e-2)\naddVarmeter!(system, device; to = \"Branch 3\", reactive = -0.044, variance = 1e-3)\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For instance, if we want to show the active power injections and the from-bus current angles, we can employ the following code:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.angle)","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nTo better understand the powers and currents associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on AC State Estimation.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Print-Results-in-the-REPL-2","page":"AC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can utilize any of the print functions outlined in the Print API. For example, to print state estimation data related to wattmeters, we can use:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"@power(MW, pu, pu)\nprintWattmeterData(system, device, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Save-Results-to-a-CSV-File","page":"AC State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintWattmeterData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Injection","page":"AC State Estimation","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC State Estimation","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC State Estimation","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-Flow","page":"AC State Estimation","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC State Estimation","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC State Estimation","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Injection","page":"AC State Estimation","title":"Current Injection","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Flow","page":"AC State Estimation","title":"Current Flow","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"manual/acStateEstimation/#Current-Through-Series-Impedance","page":"AC State Estimation","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"api/analysis/#PowerCurrentAnalysisAPI","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"In the following section, we have provided a list of functions that can be utilized for post-processing analysis. Once the voltage values are obtained through power flow analysis, optimal power flow analysis, or state estimation, these functions can be used to calculate power or current values. The specific procedures for computing these values depend on the chosen analysis, which are described in separate manuals for further information.","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"using JuliaGrid","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#AC-Power-Analysis","page":"Power and Current Analysis","title":"AC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!\ninjectionPower\nsupplyPower\nshuntPower\nfromPower\ntoPower\nseriesPower\nchargingPower\ngeneratorPower","category":"page"},{"location":"api/analysis/#AC-Current-Analysis","page":"Power and Current Analysis","title":"AC Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"current!\ninjectionCurrent\nfromCurrent\ntoCurrent\nseriesCurrent","category":"page"},{"location":"api/analysis/#DC-Power-Analysis","page":"Power and Current Analysis","title":"DC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!\ninjectionPower\nsupplyPower\nfromPower\ntoPower\ngeneratorPower","category":"page"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#ACPowerAnalysisAPI","page":"Power and Current Analysis","title":"AC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!(::PowerSystem, ::ACPowerFlow)\ninjectionPower(::PowerSystem, ::AC)\nsupplyPower(::PowerSystem, ::ACPowerFlow)\nshuntPower(::PowerSystem, ::AC)\nfromPower(::PowerSystem, ::AC)\ntoPower(::PowerSystem, ::AC)\nseriesPower(::PowerSystem, ::AC)\nchargingPower(::PowerSystem, ::AC)\ngeneratorPower(::PowerSystem, ::ACPowerFlow)","category":"page"},{"location":"api/analysis/#JuliaGrid.power!-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.power!","text":"power!(system::PowerSystem, analysis::AC)\n\nThe function computes the active and reactive powers associated with buses, branches, and generators for AC analysis.\n\nUpdates\n\nThis function updates the power field of the AC abstract type by computing the following electrical quantities:\n\ninjection: Active and reactive power bus injections.\nsupply: Active and reactive power bus injections from the generators.\nshunt: Active and reactive power values associated with shunt element at each bus.\nfrom: Active and reactive power flows at the from-bus end of each branch.\nto: Active and reactive power flows at the to-bus end of each branch.\ncharging: Active and reactive power values linked with branch charging admittances for each branch.\nseries Active and reactive power losses through each branch series impedance.\ngenerator: Produced active and reactive power outputs of each generator (not for state estimation).\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.injectionPower","text":"injectionPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power injections associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = injectionPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.supplyPower-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.supplyPower","text":"supplyPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power injections from the generators associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = supplyPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.shuntPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.shuntPower","text":"shuntPower(system::PowerSystem, analysis::AC, label)\n\nThe function returns the active and reactive power values of the shunt element associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = shuntPower(system, analysis; label = 9)\n\n```\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.fromPower","text":"fromPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power flows at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = fromPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.toPower","text":"toPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power flows at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = toPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.seriesPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.seriesPower","text":"seriesPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power losses across the series impedance of a specific branch within the AC framework. The label keyword argument should correspond to an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = seriesPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.chargingPower-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.chargingPower","text":"chargingPower(system::PowerSystem, analysis::AC; label)\n\nThe function returns the active and reactive power values associated with the charging admittances of a specific branch in the AC framework. The label keyword argument must correspond to an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = chargingPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.generatorPower-Tuple{PowerSystem, ACPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.generatorPower","text":"generatorPower(system::PowerSystem, analysis::AC)\n\nThe function returns the active and reactive powers associated with a specific generator in the AC framework. The label keyword argument must match an existing generator label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\nactive, reactive = generatorPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#ACCurrentAnalysisAPI","page":"Power and Current Analysis","title":"AC Current Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"current!(::PowerSystem, ::AC)\ninjectionCurrent(::PowerSystem, ::AC)\nfromCurrent(::PowerSystem, ::AC)\ntoCurrent(::PowerSystem, ::AC)\nseriesCurrent(::PowerSystem, ::AC)","category":"page"},{"location":"api/analysis/#JuliaGrid.current!-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.current!","text":"current!(system::PowerSystem, analysis::AC)\n\nThe function computes the currents in the polar coordinate system associated with buses and branches in the AC framework.\n\nUpdates\n\nThis function calculates various electrical quantities in the polar coordinate system:\n\ninjection: Current injections at each bus.\nfrom: Current flows at each from-bus end of the branch.\nto: Current flows at each to-bus end of the branch.\nseries: Current flows through the series impedance of the branch in the direction from the from-bus end to the to-bus end of the branch.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\ncurrent!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.injectionCurrent","text":"injectionCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current injection in the polar coordinate system associated with a specific bus in the AC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = injectionCurrent(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.fromCurrent","text":"fromCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system at the from-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = fromCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.toCurrent","text":"toCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system at the to-bus end associated with a specific branch in the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = toCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.seriesCurrent-Tuple{PowerSystem, AC}","page":"Power and Current Analysis","title":"JuliaGrid.seriesCurrent","text":"seriesCurrent(system::PowerSystem, analysis::AC; label)\n\nThe function returns the current in the polar coordinate system through series impedance associated with a specific branch in the direction from the from-bus end to the to-bus end of the branch within the AC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\nmagnitude, angle = seriesCurrent(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"","category":"page"},{"location":"api/analysis/#DCPowerAnalysisAPI","page":"Power and Current Analysis","title":"DC Power Analysis","text":"","category":"section"},{"location":"api/analysis/","page":"Power and Current Analysis","title":"Power and Current Analysis","text":"power!(::PowerSystem, ::DCPowerFlow)\ninjectionPower(::PowerSystem, ::DCPowerFlow)\nsupplyPower(::PowerSystem, ::DCPowerFlow)\nfromPower(::PowerSystem, ::DC)\ntoPower(::PowerSystem, ::DC)\ngeneratorPower(::PowerSystem, ::DCPowerFlow)","category":"page"},{"location":"api/analysis/#JuliaGrid.power!-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.power!","text":"power!(system::PowerSystem, analysis::DC)\n\nThe function calculates the active power values related to buses, branches, and generators within the DC analysis framework.\n\nUpdates\n\nThis function updates the power field of the DC abstract type by computing the following electrical quantities:\n\ninjection: Active power injections at each bus.\nsupply: Active power injections from the generators at each bus.\nfrom: Active power flows at each from-bus end of the branch.\nto: Active power flows at each to-bus end of the branch.\ngenerator: Output active powers of each generator (excluding for state estimation).\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\npower!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.injectionPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.injectionPower","text":"injectionPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power injection associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\ninjection = injectionPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.supplyPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.supplyPower","text":"supplyPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power injection from the generators associated with a specific bus in the DC framework. The label keyword argument must match an existing bus label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nsupply = supplyPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.fromPower-Tuple{PowerSystem, DC}","page":"Power and Current Analysis","title":"JuliaGrid.fromPower","text":"fromPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power flow at the from-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nfrom = fromPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.toPower-Tuple{PowerSystem, DC}","page":"Power and Current Analysis","title":"JuliaGrid.toPower","text":"toPower(system::PowerSystem, analysis::DC; label)\n\nThe function returns the active power flow at the to-bus end associated with a specific branch in the DC framework. The label keyword argument must match an existing branch label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nto = toPower(system, analysis; label = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/analysis/#JuliaGrid.generatorPower-Tuple{PowerSystem, DCPowerFlow}","page":"Power and Current Analysis","title":"JuliaGrid.generatorPower","text":"generatorPower(system::PowerSystem, analysis::DC; label)\n\nThis function returns the output active power associated with a specific generator in the DC framework. The label keyword argument must match an existing generator label.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\ngenerator = generatorPower(system, analysis; label = 1)\n\n\n\n\n\n","category":"method"},{"location":"tutorials/dcStateEstimation/#DCStateEstimationTutorials","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the DC model:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, angle = 0.0)\naddBus!(system; label = 2, type = 1, active = 0.1)\naddBus!(system; label = 3, type = 1, active = 1.3)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.2)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.1)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.3)\naddGenerator!(system; label = 1, bus = 1, active = 3.2)\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of measurement devices mathcalM into the graph mathcalG. In typical scenarios, the DC state estimation model relies solely on active power measurements originating from the set of wattmeters mathcalP. However, we provide the option for users to include measurements from the set of PMUs barmathcalP. Specifically, we utilize only the PMUs installed at the buses barmathcalP_textb subset barmathcalP that measure bus voltage angles. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEModelTutorials","page":"DC State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In accordance with the DC Model, the DC state estimation is derived through the linearization of the non-linear model. In this linearized model, all bus voltage magnitudes are assumed to be V_i approx 1, i in mathcalN. Additionally, shunt elements and branch resistances are neglected. This simplification implies that the DC model disregards reactive powers and transmission losses, focusing solely on active powers. Consequently, the DC state estimation considers only bus voltage angles, represented as mathbf x equiv bm Theta, as the state variables. As a result, the total number of state variables is n-1, with one voltage angle corresponding to the slack bus.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Within the JuliaGrid framework for DC state estimation, the methodology encompasses both active power flow and injection measurements from the set mathcalP, along with bus voltage angle measurements represented by the set barmathcalP_textb. These measurements contribute to the construction of a linear system of equations:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz=mathbfh(bm Theta)+mathbfu","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathbfh(bm Theta)= h_1(bm Theta), dots, h_k(bm Theta)^T is the vector of linear measurement functions, mathbfz = z_1dotsz_k^mathrmT is the vector of measurement values, and mathbfu = u_1dotsu_k^mathrmT is the vector of uncorrelated measurement errors, and this defines the vector of measurement variances mathbfv = v_1dotsv_k^mathrmT, where k = mathcalM.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Therefore, the linear system of equations can be represented based on the specific devices from which measurements originate, whether wattmeters or PMUs:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginbmatrix\n mathbfz_mathcalP3pt\n mathbfz_barmathcalP_textb\n endbmatrix =\n beginbmatrix\n mathbfh_mathcalP(bm Theta)3pt\n mathbfh_barmathcalP_textb(bm Theta)\n endbmatrix +\n beginbmatrix\n mathbfu_mathcalP3pt\n mathbfu_barmathcalP_textb\n endbmatrix","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In summary, upon user definition of the measurement devices, each i-th measurement device is linked to the measurement function h_i(bm Theta), the corresponding measurement value z_i, and the measurement variance v_i.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Active-Power-Injection-Measurements","page":"DC State Estimation","title":"Active Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"When adding a wattmeter P_i in mathcalP at bus i in mathcalN, users specify that the wattmeter measures active power injection and define measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_i mathbfv_mathcalP = v_P_i mathbfh_mathcalP(bm Theta) = h_P_i(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₃\", bus = 3, active = -1.30, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, utilizing the DC Model, we derive the function defining the active power injection as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_i(bm Theta) = B_iitheta_i + sum_j in mathcalN_i setminus i B_ij theta_j + P_texttri + P_textshi","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathcalN_i setminus i contains buses incident to bus i, excluding bus i, with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_i(bm Theta)mathrm partial theta_i = B_ii \n cfracmathrm partialh_P_i(bm Theta)mathrm partial theta_j = B_ij\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#From-Bus-End-Active-Power-Flow-Measurements","page":"DC State Estimation","title":"From-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Additionally, when introducing a wattmeter at branch (ij) in mathcalE, users specify that the wattmeter measures active power flow. It can be positioned at the from-bus end, denoted as P_ij in mathcalP, specifying the measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_ij mathbfv_mathcalP = v_P_ij mathbfh_mathcalP(bm Theta) = h_P_ij(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₁₂\", from = 1, active = 0.28, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, the function describing active power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_ij(bm Theta) = cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ij(bm Theta)mathrm partial theta_i = cfrac1tau_ij x_ij \n cfracmathrm partialh_P_ij(bm Theta)mathrm partial theta_j = -cfrac1tau_ij x_ij\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#To-Bus-End-Active-Power-Flow-Measurements","page":"DC State Estimation","title":"To-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, a wattmeter can be placed at the to-bus end, denoted as P_ji in mathcalP, specifying the measurement value, variance and measurement function of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_mathcalP = z_P_ji mathbfv_mathcalP = v_P_ji mathbfh_mathcalP(bm Theta) = h_P_ji(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₂₁\", to = 1, active = -0.28, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Thus, the function describing active power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_P_ji(bm Theta) = -cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expressions:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" cfracmathrm partialh_P_ji(bm Theta)mathrm partial theta_i = -cfrac1tau_ij x_ij \n cfracmathrm partialh_P_ji(bm Theta)mathrm partial theta_j = cfrac1tau_ij x_ij","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Bus-Voltage-Angle-Measurements","page":"DC State Estimation","title":"Bus Voltage Angle Measurements","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"If the user opts to include phasor measurements that measure bus voltage angle at bus i in mathcalN, denoted as theta_i in barmathcalP_textb, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz_barmathcalP_textb = z_theta_i mathbfv_barmathcalP_textb = v_theta_i mathbfh_barmathcalP_textb(bm Theta) = h_theta_i(bm Theta)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1.0, angle = 0,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-6)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, the function defining the bus voltage angle measurement is straightforward:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" h_theta_i(bm Theta) = theta_i","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"with the following coefficient expression:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" cfracmathrm partialh_theta_i(bm Theta)mathrm partial theta_i=1","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEWLSStateEstimationTutorials","page":"DC State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The solution to the DC state estimation problem is determined by solving the linear weighted least-squares (WLS) problem, represented by the following formula:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf H^T bm Sigma^-1 mathbf H bm Theta = mathbf H^T bm Sigma^-1 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, mathbf z in mathbb R^k denotes the vector of measurement values, the vector mathbf c in mathbb R^k holds constant terms, mathbf H in mathbb R^k times (n-1) represents the coefficient matrix, and bm Sigma in mathbb R^k times k is the measurement error covariance matrix, where the diagonal elements hold measurement variances.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The inclusion of the vector mathbfc is necessary due to the fact that measurement functions associated with active power measurements may include constant terms, especially when there are non-zero shift angles of transformers or shunt elements in the system consuming active powers, as evident from the provided measurement functions.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Implementation","page":"DC State Estimation","title":"Implementation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuliaGrid initiates the DC state estimation framework by setting up the WLS model, as illustrated in the following:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Coefficient-Matrix","page":"DC State Estimation","title":"Coefficient Matrix","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Using the above-described equations, JuliaGrid forms the coefficient matrix mathbfH in mathbbR^k times (n-1):","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐇 = analysis.method.coefficient","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Each row in the matrix corresponds to a specific measurement. The first mathcalP rows correspond to wattmeters, ordered as users add wattmeters, while the last barmathcalP_textb rows correspond to PMUs, also in the order users add PMUs.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Precision-Matrix","page":"DC State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuliaGrid opts not to retain the covariance matrix bm Sigma but rather stores its inverse, the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. The order of these values corresponds to the description provided for the coefficient matrix. Users can access these values using the following command:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Mean-Vector","page":"DC State Estimation","title":"Mean Vector","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can access the vector mathbf z - mathbfc, which contains the means of Gaussian distributions describing each measurement, using the following command:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In the context of the power system, where phase-shifting transformers and shunt elements consuming active powers are absent, and the slack angle has a zero value, the vector mathbfc= mathbf0. Consequently, the vector of means holds values that are equal to the measurement values.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Estimate-of-State-Variables","page":"DC State Estimation","title":"Estimate of State Variables","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Once the model is established, we solve the WLS equation to derive the estimate of bus voltage angles:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\thatbm Theta = mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T bm Sigma^-1 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This process is executed using the solve! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The initial step involves the LU factorization of the gain matrix:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf G = mathbf H^T bm Sigma^-1 mathbf H = mathbf L mathbf U","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the gain matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Access to the factorized gain matrix is available through:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Finally, the estimated bus voltage angles hatbm Theta = hattheta_i, i in mathcalN, can be retrieved using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It is essential to note that the slack bus voltage angle is temporarily excluded from the gain matrix mathbf G during computation. It is important to emphasize that this internal handling does not alter the stored elements.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEOrthogonalWLSStateEstimationTutorials","page":"DC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can employ an alternative approach:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device, Orthogonal)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"\tmathbf H^T mathbf W mathbf H bm Theta = mathbf H^T mathbf W (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf H bm Theta = left(mathbf W^12 mathbf Hright)^T mathbf W^12 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH^T barmathbfH bm Theta = barmathbfH^T barmathbfz","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH = mathbf W^12 mathbf H barmathbfz = mathbf W^12 (mathbf z - mathbfc)","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"At this point, QR factorization is performed on the rectangular matrix:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barmathbfH = mathbf W^12 mathbf H = mathbfQmathbfR","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Executing this procedure involves the solve! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain the solution, JuliaGrid avoids materializing the orthogonal matrix mathbfQ and proceeds to solve the system, resulting in the estimate of state variables hatbm Theta = hattheta_i, where i in mathcalN:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEBadDataTutorials","page":"DC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; label = \"P₁\", bus = 1, active = 13.1, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, we will construct the WLS state estimation model and solve it:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" r_i = z_i - h_i(hat bm Theta) i in mathcalM","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf H mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"is removed from the DC model and marked as out-of-service.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, we can immediately solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSELAVTutorials","page":"DC State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"It can be demonstrated that the problem can be expressed as a linear programming problem. This section outlines the method as described in [5, Sec. 6.5]. To revisit, we consider the system of linear equations:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbfz=mathbfh(bm Theta)+mathbfu","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n textminimize mathbf a^T mathbf r\n textsubjectto mathbfz - mathbfHbm Theta - mathbfc =mathbf r\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Here, mathbf a in mathbb R^k is the vector with all entries equal to one, and mathbf r represents the vector of measurement residuals. Let bm eta be defined in a manner that ensures:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" mathbf r preceq bm eta","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"and replace the above inequality with two equalities using the introduction of two non-negative slack variables mathbf q in mathbb R_ge 0^k and mathbf w in mathbb R_ge 0^k:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r - mathbf q = -bm eta \n mathbf r + mathbf w = bm eta\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Let us now define four additional non-negative variables:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" bm Theta_x in mathbb R_ge 0^n bm Theta_y in mathbb R_ge 0^n \n mathbf r_x in mathbb R_ge 0^k mathbf r_y in mathbb R_ge 0^k","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"where:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" bm Theta = bm Theta_x - bm Theta_y mathbf r = mathbf r_x - mathbf r_y\n mathbf r_x = cfrac12 mathbf q mathbf r_y = cfrac12 mathbf w","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r - 2mathbf r_x = -2bm eta \n mathbf r + 2 mathbf r_y = 2bm eta\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"that is:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n mathbf r_x + mathbf r_y = bm eta mathbf r = mathbf r_x - mathbf r_y\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" beginaligned\n textminimize mathbf a^T (mathbf r_x + mathbf r_y)\n textsubjectto mathbfH(bm Theta_x - bm Theta_y) + mathbf r_x - mathbf r_y = mathbfz - mathbfc \n bm Theta_x succeq mathbf 0 bm Theta_y succeq mathbf 0 \n mathbf r_x succeq mathbf 0 mathbf r_y succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"As a result, we obtain optimal values for the four additional non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" hatbm Theta = bm Theta_x - bm Theta_y","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can retrieve the estimated bus voltage angles hatbm Theta = hattheta_i, i in mathcalN, using the variable:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#DCSEPowerAnalysisTutorials","page":"DC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution from the DC state estimation, we can calculate powers related to buses and branches using the power! function:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Power-Injections","page":"DC State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Generator-Power-Injections","page":"DC State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can determine the active power supplied by generators to the buses by summing the active power injections and the active power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":" P_textpi = P_i + P_textdi i in mathcalN","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The vector of active power injected by generators into the buses, denoted by mathbfP_textp = P_textpi, can be obtained using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"tutorials/dcStateEstimation/#Power-Flows","page":"DC State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resulting active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, the resulting active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"tutorials/powerSystemModel/#ACDCModelTutorials","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Power system analyses commonly utilize the unified branch model that provides linear relationships between voltages and currents. However, as the focus is on power calculations rather than current calculations, the resulting equations become nonlinear, posing challenges in solving them [6]. Hence, to accurately analyze power systems without any approximations, we use the AC model, which is a crucial component of our framework. In contrast, to obtain a linear system of equations for various DC analyses, we introduce approximations in the unified branch model, resulting in the DC model.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIn this section, we not only describe the AC and DC models derived from the unified branch model but also furnish the power and current equations utilized in all JuliaGrid analyses.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"A common way to describe the power system network topology is through the bus/branch model, which employs the two-port pi-model, which results in the unified branch model. The bus/branch model can be represented by a graph denoted by mathcalG = (mathcalN mathcalE), where the set of nodes mathcalN = 1 dots n corresponds to buses, and the set of edges mathcalE subseteq mathcalN times mathcalN represents the branches of the power network.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us now construct the power system:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7, reactive = 12.7)\naddBus!(system; label = 3, type = 2, conductance = 2.1, susceptance = 1.2)\n\naddBranch!(system; from = 1, to = 2, resistance = 0.02, reactance = 0.06, susceptance = 0.05)\naddBranch!(system; from = 2, to = 3, reactance = 0.21, turnsRatio = 0.98, shiftAngle = 1.2)\n\naddGenerator!(system; bus = 1, active = 40.0, reactive = 42.4)\nnothing #hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The given example provides the set of buses mathcalN and the set of branches mathcalE:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_ij, where a_ij represents the generic element associated with the branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#ACModelTutorials","page":"Power System Model","title":"AC Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid is based on common network elements and benefits from the unified branch model to perform various analyses based on the system of nonlinear equations. To generate matrices and vectors for AC or nonlinear analysis, JuliaGrid employs the acModel! function:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"acModel!(system)\nnothing #hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#UnifiedBranchModelTutorials","page":"Power System Model","title":"Unified Branch Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The equivalent unified pi-model for a branch (ij) in mathcalE incident to the buses ij in mathcalN is shown in Figure 1.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 1: The equivalent branch model, where the transformer is located at the from-bus end of the branch.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe directions of the currents barI_ij, barI_ji, barI_textsi, and barI_textsj are vital for power flow analysis. Positive power aligns with the assumed current direction, moving away from the bus, while negative power implies a reverse flow towards the bus. JuliaGrid consistently uses these directions, along with barI_textlij, for power and current calculations.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch series admittance y_ij is inversely proportional to the branch series impedance z_ij:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" y_ij = frac1z_ij = frac1r_ij + textjx_ij =\n fracr_ijr_ij^2 + x_ij^2 - textjfracx_ijr_ij^2 + x_ij^2 = g_ij + textjb_ij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where r_ij is a resistance, x_ij is a reactance, g_ij is a conductance and b_ij is a susceptance of the branch.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vectors of resistances, denoted by mathbfr = r_ij, and reactances, denoted by mathbfx = x_ij, are stored in the variables:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐫 = system.branch.parameter.resistance\n𝐱 = system.branch.parameter.reactance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, the ac field stores the computed vector of branch series admittances mathbfy = y_ij:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲 = system.model.ac.admittance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch shunt admittance y_textsij is equal to:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"y_textsij = g_textsij + textjb_textsij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where g_textsij represents the shunt conductance of the branch, and b_textsij represents the shunt susceptance. Both of these values are positive for real line sections. It is worth noting that while the shunt conductance g_textsij is often insignificantly small and can be ignored in many cases, it is included in the analyses to ensure comprehensive consideration of all potential scenarios.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Within JuliaGrid, the total shunt conductances and susceptances of branches are stored. In order to obtain the vectors mathbfg_texts = g_textsij and mathbfb_texts = b_textsij, the conductances and susceptances must be distributed by considering the ends of the branches:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐠ₛ = 0.5 * system.branch.parameter.conductance\n𝐛ₛ = 0.5 * system.branch.parameter.susceptance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The transformer complex ratio alpha_ij is defined:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" alpha_ij = cfrac1tau_ije^-textjphi_ij","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where tau_ij neq 0 is a transformer turns ratio, while phi_ij is a transformer phase shift angle, always located at the from-bus end of the branch. Note, if tau_ij = 1 and phi_ij = 0 the model describes the line. In-phase transformers are defined if tau_ij neq 1, phi_ij = 0, and y_textsij = 0, while phase-shifting transformers are obtained if tau_ij neq 1, phi_ij neq 0, and y_textsij = 0.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"These transformer parameters are stored in the vectors bmtau = tau_ij and bmphi = phi_ij, respectively:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝛕 = system.branch.parameter.turnsRatio\n𝚽 = system.branch.parameter.shiftAngle","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchShuntElementsTutorials","page":"Power System Model","title":"Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The currents flowing through shunt admittances denoted as y_textsij are defined as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_textsi = alpha_ij y_textsijbarV_i (ij) in mathcalE \n barI_textsj = y_textsijbarV_j (ij) in mathcalE\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"With these specified currents in place, it becomes straightforward to compute both the total active and reactive power that branch shunt elements demand and inject concerning the power system:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textsij = P_textsij + textjQ_textsij = alpha_ij barV_i barI_textsi^* + barV_j barI_textsj^* = y_textsij^*(alpha_ij^2 V_i^2 + V_j^2) (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For real branch sections, the reactive power is negative, Q_textsij 0, signifying that the branch injects reactive power due to its capacitive nature. The negative sign implies that the power flow direction opposes the assumed direction set by the currents barI_textsi and barI_textsj. The active power P_textsij represents active losses within the branch shunt admittances.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchSeriesElementTutorials","page":"Power System Model","title":"Branch Series Element","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The current flowing through a series admittance, denoted as y_ij, is defined as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" barI_textlij = alpha_ij y_ijbarV_i - y_ijbarV_i (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Consequently, the active and reactive powers associated with the branch series element are as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textlij = P_textlij + textjQ_textlij = (alpha_ij barV_i - barV_j) barI_textlij^* = y_ij^* (alpha_ij barV_i - barV_j) (alpha_ij barV_i - barV_j)^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power P_textlij accounts for losses originating from the resistance r_ij of the branch, while the reactive power Q_textlij represents losses resulting from the inductive characteristics of the impedance defined by reactance x_ij. This can be observed when the reactive power is positive Q_textlij 0.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BranchNetworkEquationsTutorials","page":"Power System Model","title":"Branch Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Using Kirchhoff's circuit laws, the branch model can be described by complex expressions:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_ij barI_ji\n endbmatrix =\n beginbmatrix\n cfrac1tau_ij^2(y_ij + y_textsij) -alpha_ij^*y_ij\n -alpha_ijy_ij y_ij + y_textsij\n endbmatrix\n beginbmatrix\n barV_i barV_j\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The admittance parameters are stored in the vectors mathbfy_textii = (y_ij + y_textsij) tau_ij^2, mathbfy_textij = -alpha_ij^*y_ij, mathbfy_textji = -alpha_ijy_ij, and mathbfy_textjj = y_ij + y_textsij and can be found in the variables:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲ᵢᵢ = system.model.ac.nodalFromFrom\n𝐲ᵢⱼ = system.model.ac.nodalFromTo\n𝐲ⱼᵢ = system.model.ac.nodalToFrom\n𝐲ⱼⱼ = system.model.ac.nodalToTo","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this context, we have easily derived the active and reactive power flow at the from-bus end of the branch:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_ij = P_ij + textjQ_ij = barV_i leftcfrac1tau_ij^2(y_ij + y_textsij) barV_i - alpha_ij^*y_ij barV_jright^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, we can determine the active and reactive power flow at the to-bus end of the branch:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_ji = P_ji + textjQ_ji = barV_j left-alpha_ijy_ij barV_i + (y_ij + y_textsij) barV_jright^* (ij) in mathcalE","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Positive values of active or reactive power, P_ij 0 or Q_ij 0, indicate power flow originating from the from-bus and moving towards the to-bus, following the direction of the current barI_ij. Conversely, negative values, P_ij 0 or Q_ij 0, signify power flow in the opposite direction. The same principles apply to P_ji 0 or Q_ji 0, indicating power flow from the to-bus to the from-bus, aligned with the current barI_ji, while negative values, P_ji 0 or Q_ji 0, denote the reverse flow direction.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#NodalNetworkEquationsTutorials","page":"Power System Model","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us consider an illustrative example from our case study, depicted in Figure 2. This example provides a smooth transition to the general case, demonstrating a system with three buses represented as mathcalN = 1 2 3 and two branches mathcalE = (1 2) (2 3), where bus 2 is incident to the shunt element with admittance y_textsh2.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 2: The example of the system with three buses and two branches.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe current barI_textsh2 follows the convention of coming out from the bus in terms of its direction. When calculating powers related to shunt elements, this current direction is assumed. Therefore, in cases where power is positive, it signifies alignment with the assumed current direction, emerging away from the bus. Conversely, when power is negative, the direction is reversed, indicating a flow towards the bus.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"According to the Branch Network Equations each branch is described using the system of equations as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_12 barI_21\n endbmatrix =\n beginbmatrix\n cfrac1tau_12^2(y_12 + y_texts12) -alpha_12^*y_12\n -alpha_12y_12 y_12 + y_texts12\n endbmatrix\n beginbmatrix\n barV_1 barV_2\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_23 barI_32\n endbmatrix =\n beginbmatrix\n cfrac1tau_23^2(y_23 + y_texts23) -alpha_23^*y_23\n -alpha_23y_23 y_23 + y_texts23\n endbmatrix\n beginbmatrix\n barV_2 barV_3\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The complex current injections at buses are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_1 = barI_12 = cfrac1tau_12^2(y_12 + y_texts12) barV_1 -alpha_12^*y_12 barV_2 \n barI_2 = barI_21 + barI_23 + barI_textsh2 = -alpha_12y_12 barV_1 + (y_12 + y_texts12) barV_2 +\n cfrac1tau_23^2(y_23 + y_texts23) barV_2 -alpha_23^*y_23 barV_3 + y_textsh2 barV_2 \n barI_3 = barI_32 = -alpha_23y_23 barV_2 + (y_23 + y_texts23) barV_3\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The system of equations can be written in the matrix form:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_1 barI_2 barI_3\n endbmatrix =\n beginbmatrix\n cfrac1tau_12^2(y_12 + y_texts12) -alpha_12^*y_12 0 \n -alpha_12y_12 y_12 + y_texts12 + cfrac1tau_23^2(y_23 + y_texts23) + y_textsh2 -alpha_23^*y_23 \n 0 -alpha_23y_23 y_23 + y_texts23\n endbmatrix\n beginbmatrix\n barV_1 barV_2 barV_3\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This system of equations can be generalized to accommodate the scenario where the set mathcalN comprises n buses:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" mathbf bar I = mathbfY mathbf bar V","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where mathbf bar V in mathbbC^n is the vector of bus complex voltages, and mathbf bar I in mathbbC^n is the vector of complex current injections at buses. The matrix mathbfY = mathbfG + textjmathbfB in mathbbC^n times n is the bus or nodal admittance matrix, with elements:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"the diagonal elements, where i in mathcalN, are equal to:\nY_ii = G_ii + textjB_ii = y_textshi +\nsumlimits_e in mathcalE e(1) = i cfrac1tau_ij^2(y_ij + y_textsij) + sumlimits_e in mathcalE e(2) = i (y_ji + y_textsji)\nthe non-diagonal elements, where i = e(1) j = e(2) e in mathcalE, are equal to:\n beginaligned\n Y_ij = G_ij + textjB_ij = -alpha_ij^*y_ij 4pt\n Y_ji = G_ji + textjB_ji = -alpha_ijy_ij\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When a branch is not incident (or adjacent) to a bus the corresponding element in the nodal admittance matrix mathbfY is equal to zero. The nodal admittance matrix mathbfY is sparse (i.e., a small number of elements are non-zeros) for real-world power systems. Although it is often assumed that the matrix mathbfY is symmetrical, it is not a general case. For example, in the presence of phase shifting transformers the matrix mathbfY is not symmetric [7, Sec. 9.6]. JuliaGrid stores both the matrix mathbfY and its transpose mathbfY^T in the ac field of the PowerSystem type:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐘 = system.model.ac.nodalMatrix\n𝐘ᵀ = system.model.ac.nodalMatrixTranspose","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BusInjectionsTutorials","page":"Power System Model","title":"Bus Injections","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"From the previous analysis, we can determine the complex current injection at each bus as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" barI_i = sumlimits_j = 1^n Y_ij barV_j i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Furthermore, the calculation of active and reactive power injection at each bus is expressed by the following equation:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_i = P_i + textjQ_i = barV_i sumlimits_j = 1^n Y_ij^* barV_j^* i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Positive values of active or reactive powers, P_i 0 or Q_i 0, indicate that the bus is supplying power into the power system. Conversely, negative values, P_i 0 or Q_i 0, suggest that the bus is drawing active or reactive power from the power system.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#BusShuntElementTutorials","page":"Power System Model","title":"Bus Shunt Element","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Based on the previous analysis, we can determine the active and reactive power at the shunt element of each bus using the following equation:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" S_textshi = P_textshi + textjQ_textshi = barV_ibarI_textshi^* = y_textshi^*V_i^2 i in mathcalN","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The positive active power value P_textshi 0 indicates that the shunt element is consuming active power. In terms of power flow, this signifies that active power flows from bus i in mathcalN towards the ground. A negative reactive power value Q_textshi 0 suggests that the shunt element is injecting reactive power into the power system. This implies that the direction of reactive power is from the ground to bus i in mathcalN, illustrating the capacitive nature of the shunt component. Conversely, if Q_textshi 0, it indicates an inductive characteristic, implying that the shunt component is absorbing reactive power.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCModelTutorials","page":"Power System Model","title":"DC Model","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The DC model is obtained by linearization of the nonlinear model, and it provides an approximate solution. In the typical operating conditions, the difference of bus voltage angles between adjacent buses (ij) in mathcalE is very small theta_i-theta_j approx 0, which implies cos (theta_i-theta_j)approx 1 and sin (theta_i-theta_j) approx theta_i-theta_j. Further, all bus voltage magnitudes are V_i approx 1, i in mathcalN, and all branch shunt admittances and branch resistances can be neglected. This implies that the DC model ignores the reactive powers and transmission losses and takes into account only the active powers.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Therefore, the DC power flow takes only bus voltage angles bm Theta in mathbbR^n as variables. To create vectors and matrices related to DC or linear analyses, JuliaGrid uses the function dcModel!:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCBranchNetworkEquationsTutorials","page":"Power System Model","title":"Branch Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"According to the above assumptions, we start from the Unified Branch Model:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n barI_ij barI_ji\n endbmatrix = cfrac1textjx_ij\n beginbmatrix\n cfrac1tau_ij^2 -alpha_ij^*\n -alpha_ij 1\n endbmatrix\n beginbmatrix\n barV_i barV_j\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where barV_i = texte^textjtheta_i and barV_j = texte^textjtheta_j. Further, we have:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n barI_ij = cfrac1textjx_ij leftcfrac1tau_ij^2 texte^textjtheta_i -\n cfrac1tau_ijtexte^textj(phi_ij + theta_j) right \n barI_ji = cfrac1textjx_ij left-cfrac1tau_ijtexte^textj(theta_i - phi_ij) + texte^textjtheta_j right\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power flows are derived as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_ij = RebarV_ibarI_ij^* =\n Re lefttextjcfrac1x_ij\n leftcfrac1tau_ij^2 - cfrac1tau_ije^textj(theta_i - theta_j - phi_ij) right right \n P_ji = RebarV_jbarI_ji^* =\n Re lefttextjcfrac1x_ij\n left1-cfrac1tau_ije^textj(-theta_i +theta_j + phi_ij) right right\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The real components are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_ij =cfrac1tau_ijx_ij sin(theta_i -theta_j-phi_ij) approx cfrac1tau_ij x_ij (theta_i -theta_j-phi_ij) \n P_ji =cfrac1tau_ijx_ij sin(theta_j -theta_i+phi_ij) approx -cfrac1tau_ij x_ij (theta_i - theta_j-phi_ij)\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where 1(tau_ij x_ij) represents the branch admittance in the DC framework. To recall, the PowerSystem type stores the reactances as vector mathbfx = x_ij in the variable:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐱 = system.branch.parameter.reactance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Furthermore, the computed branch admittances in the DC framework are stored in the vector mathbfy = 1(tau_ij x_ij):","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐲 = system.model.dc.admittance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can conclude that P_ij=-P_ji holds. With the DC model, the linear network equations relate active powers to bus voltage angles, versus complex currents to complex bus voltages in the AC model [8]. Consequently, analogous to the Branch Network Equations we can write:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_ij P_ji\n endbmatrix = cfrac1tau_ijx_ij\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_i theta_j\n endbmatrix + cfracphi_ijtau_ijx_ij\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCNodalNetworkEquationsTutorials","page":"Power System Model","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As before, let us consider an illustrative example from our case study, depicted in Figure 3. This example provides a smooth transition to the general case, demonstrating a system with three buses represented as mathcalN = 1 2 3 and two branches mathcalE = (1 2) (2 3), where bus 2 is incident to the shunt element with admittance g_textsh2.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"\n
Figure 3: The example of the system with three buses and two branches.
\n ","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Each branch in the DC framework is described with a system of equations as follows:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_12 P_21\n endbmatrix = cfrac1tau_12x_12\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_1 theta_2\n endbmatrix + cfracphi_12tau_12x_12\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_23 P_32\n endbmatrix = cfrac1tau_23x_23\n beginbmatrix\n 1 -1\n -1 1\n endbmatrix\n beginbmatrix\n theta_2 theta_3\n endbmatrix + cfracphi_23tau_23x_23\n beginbmatrix\n -1 1\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The active power injections at buses are:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginaligned\n P_1 = P_12 =cfrac1tau_12x_12 theta_1 - cfrac1tau_12x_12 theta_2 - cfracphi_12tau_12x_12 \n P_2 = P_21 + P_23 + P_textsh2 = -cfrac1tau_12x_12 theta_1 + cfrac1tau_12x_12 theta_2 + cfracphi_12tau_12x_12 +\n cfrac1tau_23x_23 theta_2 - cfrac1tau_23x_23 theta_3 - cfracphi_23tau_23x_23 + g_textsh2 \n P_3 = P_32 = -cfrac1tau_23x_23 theta_2 +cfrac1tau_23x_23 theta_3 + cfracphi_23tau_23x_23\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where the active power injected by the shunt element at the bus 2 is equal to:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" P_textsh2 = RebarV_2barI_textsh2^* = RebarV_2y_textsh2^*barV_2^* = V_2^2 g_textsh2 = g_textsh2","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The system of equations can be written in the matrix form:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" beginbmatrix\n P_1 P_2 P_3\n endbmatrix =\n beginbmatrix\n cfrac1tau_12x_12 - cfrac1tau_12x_12 0 \n -cfrac1tau_12x_12 cfrac1tau_12x_12 + cfrac1tau_23x_23 -cfrac1tau_23x_23 \n 0 -cfrac1tau_23x_23 cfrac1tau_23x_23\n endbmatrix\n beginbmatrix\n theta_1 theta_2 theta_3\n endbmatrix +\n beginbmatrix\n - cfracphi_12tau_12x_12 cfracphi_12tau_12x_12 - cfracphi_23tau_23x_23 cfracphi_23tau_23x_23\n endbmatrix +\n beginbmatrix\n 0 g_textsh2 0\n endbmatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This system of equations can be generalized to accommodate the scenario where the set mathcalN comprises n buses:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" mathbf P = mathbfB bm Theta + mathbfP_texttr + mathbfP_textsh","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"where bm Theta in mathbbR^n is the vector of bus voltage angles.","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbf P in mathbbR^n contains active power injections at buses caused by generators and demands. In JuliaGrid, the vector can be recovered using a command:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏 = system.bus.supply.active - system.bus.demand.active","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbfP_texttr in mathbbR^n represents active powers related to the non-zero shift angle of transformers. This vector is stored in the dc field, and we can access it using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏ₜᵣ = system.model.dc.shiftPower","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The vector mathbfP_textsh in mathbbR^n represents active powers consumed by shunt elements. We can access this vector using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐏ₛₕ = system.bus.shunt.conductance","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The bus or nodal matrix in the DC framework is given as mathbfB in mathbbR^n times n, with elements:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"the diagonal elements, where i in mathcalN, are equal to:\nB_ii = sumlimits_e in mathcalE i in e cfrac1tau_ijx_ij\nthe non-diagonal elements, where i = e(1) j = e(2) e in mathcalE, are equal to:\n beginaligned\n B_ij = -cfrac1tau_ijx_ij 3pt\n B_ji = -cfrac1tau_ijx_ij\n endaligned","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The sparse nodal matrix mathbfB is stored in the dc field, and we can access it using:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"𝐁 = system.model.dc.nodalMatrix","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"tutorials/powerSystemModel/#DCBusInjectionTutorials","page":"Power System Model","title":"Bus Injection","text":"","category":"section"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"From the previous analysis, the calculation of active power injection at each bus is expressed by:","category":"page"},{"location":"tutorials/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":" P_i = sum_j = 1^n B_ij theta_j + P_texttri + P_textshi i in mathcalN","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowManual","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similar to AC Optimal Power Flow, JuliaGrid utilizes the JuMP package to construct optimal power flow models, enabling users to manipulate these models using the standard functions provided by JuMP. JuliaGrid supports popular solvers mentioned in the JuMP documentation to solve the optimization problem.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To perform the DC optimal power flow, we first need to have the PowerSystem type that has been created with the DC model. After that, create the DCOptimalPowerFlow type to establish the DC optimal power flow framework using the function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"dcOptimalPowerFlow.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To solve the DC optimal power flow problem and acquire generator active power outputs and bus voltage angles, make use of the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"solve!.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution for DC optimal power flow, JuliaGrid offers a post-processing analysis function to compute powers associated with buses and branches:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses, branches, or generators.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowModelManual","page":"DC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To set up the DC optimal power flow, we begin by creating the model. To illustrate this, consider the following:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, HiGHS\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05)\n\n@branch(minDiffAngle = -3.1, maxDiffAngle = 3.1, minFromBus = -0.12, maxFromBus = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.6, maxActive = 0.8)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.1, maxActive = 0.3)\naddGenerator!(system; label = \"Generator 3\", bus = \"Bus 2\", active = 0.2, maxActive = 0.4)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [8.0 11.0; 14.0 17.0])\ncost!(system; label = \"Generator 3\", active = 1, piecewise = [6.8 12.3; 8.7 16.8; 11.2 19.8])\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, the dcOptimalPowerFlow function is utilized to formulate the DC optimal power flow problem:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimizationVariablesManual","page":"DC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In DC optimal power flow, generator active power outputs are linear functions of bus voltage angles. Thus, the model's variables include generator active power outputs and bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.all_variables(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is important to highlight that when dealing with linear piecewise cost functions comprising multiple segments, as exemplified in the case of Generator 3, JuliaGrid automatically generates helper optimization variables, such as actwise[3], and formulates a set of linear constraints to appropriately handle these cost functions.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"However, in instances where a linear piecewise cost function consists of only a single segment, as demonstrated by Generator 2, the function is modelled as a standard linear function, eliminating the necessity for additional helper optimization variables.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Please note that JuliaGrid keeps references to all variables categorized into three fields:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.variable))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Variable-Names","page":"DC Optimal Power Flow","title":"Variable Names","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the option to define custom variable names for printing and writing equations, which can help present them in a more compact form. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer; active = \"P\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-Variables","page":"DC Optimal Power Flow","title":"Add Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The user has the ability to easily add new variables to the defined DC optimal power flow model by using the @variable macro from the JuMP package:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.@variable(analysis.method.jump, newVariable)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We can verify that the new variable is included in the defined model by using the function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Delete-Variables","page":"DC Optimal Power Flow","title":"Delete Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To delete a variable, the delete function from the JuMP package can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After deletion, the variable is no longer part of the model:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCConstraintFunctionsManual","page":"DC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuliGrid keeps track of all the references to internally formed constraints in the constraint field of the DCOptimalPowerFlow type. These constraints are divided into six fields:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.constraint))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nWe suggest that readers refer to the tutorial on DC Optimal Power Flow for insights into the implementation.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Slack-Bus-Constraint","page":"DC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The slack field contains a reference to the equality constraint associated with the fixed bus voltage angle value of the slack bus. This constraint is set within the addBus! function using the angle keyword:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the flexibility to modify this constraint by changing which bus serves as the slack bus and by adjusting the value of the bus angle. This can be achieved using the updateBus! function, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", angle = -0.1)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated slack constraint can be inspected as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Bus-Active-Power-Balance-Constraints","page":"DC Optimal Power Flow","title":"Bus Active Power Balance Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The balance field contains references to the equality constraints associated with the active power balance equations defined for each bus. The constant terms in these equations are determined by the active and conductance keywords within the addBus! function. Additionally, if there are phase shift transformers in the system, the constant terms can also be affected by the shiftAngle keyword within the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"During the execution of functions that add or update power system components, these constraints are automatically adjusted to reflect the current configuration of the power system, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 3\", active = 0.1)\nupdateGenerator!(system, analysis; label = \"Generator 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power balance constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Bus-Voltage-Angle-Difference-Constraints","page":"DC Optimal Power Flow","title":"Bus Voltage Angle Difference Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The voltage field contains references to the inequality constraints associated with the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch. These values are specified using the minDiffAngle and maxDiffAngle keywords within the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nPlease note that if the limit constraints are set to minDiffAngle = -2π and maxDiffAngle = 2π for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, by employing the updateBranch! function, we have the ability to modify these constraints as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", minDiffAngle = -1.7, maxDiffAngle = 1.7)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of voltage angle difference constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Branch-Active-Power-Flow-Constraints","page":"DC Optimal Power Flow","title":"Branch Active Power Flow Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The flow field refers to the inequality constraints associated with active power flow limits at the from-bus end of each branch. These limits are set using the minFromBus and maxFromBus keywords in the addBranch! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nIf the branch flow limits are set to minFromBus = 0.0 and maxFromBus = 0.0 for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By employing the updateBranch! function, we have the ability to modify these specific constraints, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", status = 0)\nupdateBranch!(system, analysis; label = \"Branch 2\", reactance = 0.03, maxFromBus = 0.14)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power flow constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Generator-Active-Power-Capability-Constraints","page":"DC Optimal Power Flow","title":"Generator Active Power Capability Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The capability field contains references to the inequality constraints associated with the minimum and maximum active power outputs of the generators. These limits are specified using the minActive and maxActive keywords within the addGenerator! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As demonstrated, the active power output of Generator 2 is currently fixed at zero due to the earlier action of setting this generator out-of-service. Let us adjust this specific constraint using the updateGenerator! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", status = 1, maxActive = 0.5)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Subsequently, the updated set of active power capability constraints can be examined as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is important to note that bringing back Generator 2 into service will also have an impact on the balance constraint, which will once again be influenced by the generator's output.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Piecewise-Constraints","page":"DC Optimal Power Flow","title":"Active Power Piecewise Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the context of active power modelling, the piecewise field serves as a reference to the inequality constraints related to linear piecewise cost functions. These constraints are created using the cost! function with active = 1 specified when dealing with linear piecewise cost functions comprising multiple segments. JuliaGrid takes care of establishing the appropriate inequality constraints for each segment of the linear piecewise cost:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.piecewise.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"It is worth noting that these constraints can also be automatically updated using the cost! function, and readers can find more details in the section about the objective function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-Constraints","page":"DC Optimal Power Flow","title":"Add Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can effortlessly introduce additional constraints into the defined DC optimal power flow model by utilizing the addBranch! or addGenerator! functions. Specifically, if a user wishes to include a new branch or generator in an already defined PowerSystem and DCOptimalPowerFlow type:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"addBranch!(system, analysis; label = \"Branch 4\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\naddGenerator!(system, analysis; label = \"Generator 4\", bus = \"Bus 1\", maxActive = 0.2)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As a result, the flow and capability constraints will be adjusted as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.active)\nprint(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Add-User-Defined-Constraints","page":"DC Optimal Power Flow","title":"Add User-Defined Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users also have the option to include their custom constraints within the established DC optimal power flow model by employing the @constraint macro. For example, the addition of a new constraint can be achieved as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.@constraint(analysis.method.jump, 0.0 <= analysis.method.variable.active[4] <= 0.3)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Delete-Constraints","page":"DC Optimal Power Flow","title":"Delete Constraints","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To delete a constraint, users can make use of the delete function from the JuMP package. When handling constraints that have been internally created, users can refer to the constraint references stored in the constraint field of the DCOptimalPowerFlow type.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"For example, if the intention is to eliminate constraints related to the capability of Generator 4, the following code snippet can be employed:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, analysis.method.constraint.capability.active[4])\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nIn the event that a user deletes a constraint and subsequently executes a function that updates bus, branch, or generator parameters, and if the deleted constraint is affected by these functions, JuliaGrid will automatically reinstate that constraint. Users should exercise caution when deleting constraints, as this action is considered potentially harmful since it operates independently of power system data.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCObjectiveFunctionManual","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The objective function of the DC optimal power flow is constructed using polynomial and linear piecewise cost functions of the generators, which are defined using the cost! functions. It is important to note that only polynomial cost functions up to the second degree are included in the objective. If there are polynomials of higher degrees, JuliaGrid will exclude them from the objective function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the provided example, the objective function that needs to be minimized to obtain the optimal values of the active power outputs of the generators and the bus voltage angles is as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Additionally, JuliaGrid stores the objective function in a separate variable, allowing users to access it by referencing the variable analysis.objective.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Update-Objective-Function","page":"DC Optimal Power Flow","title":"Update Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By utilizing the cost! functions, users have the flexibility to modify the objective function by adjusting polynomial or linear piecewise cost coefficients or by changing the type of polynomial or linear piecewise function employed. For instance, consider Generator 3, which incorporates a piecewise cost structure with two segments. Now, we can define a polynomial function for this generator and activate it by specifying the keyword active = 2 as shown:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"cost!(system, analysis; label = \"Generator 3\", active = 2, polynomial = [853.4; 257; 40])","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"This results in the updated objective function, which can be observed as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.objective","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#User-Defined-Objective-Function","page":"DC Optimal Power Flow","title":"User-Defined Objective Function","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can modify the objective function using the set_objective_function function from the JuMP package. This operation is considered destructive because it is independent of power system data; however, in certain scenarios, it may be more straightforward than using the cost! function for updates. Moreover, using this methodology, users can combine a defined function with a newly defined expression. Here is an example of how it can be achieved:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"expr = 100.2 * analysis.method.variable.active[1] * analysis.method.variable.active[1] + 123\nJuMP.set_objective_function(analysis.method.jump, analysis.method.objective - expr)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We can now observe the updated objective function as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#SetupStartingPrimalValuesManual","page":"DC Optimal Power Flow","title":"Setup Starting Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In JuliaGrid, the assignment of starting primal and dual values for optimization variables takes place when the solve! function is executed.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Starting-Primal-Values","page":"DC Optimal Power Flow","title":"Starting Primal Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Starting primal values are determined based on the generator and voltage fields within the DCOptimalPowerFlow type. By default, these values are initially established using the active power outputs of the generators and the initial bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users have the flexibility to adjust these values according to their specifications, which will then be used as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Using-DC-Power-Flow","page":"DC Optimal Power Flow","title":"Using DC Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this perspective, users have the capability to conduct the DC power flow analysis and leverage the resulting solution to configure starting primal values. Here is an illustration of how this can be achieved:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"flow = dcPowerFlow(system)\nsolve!(system, flow)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution, we can calculate the active power outputs of the generators and utilize the bus voltage angles to set the starting values. In this case, the generator and voltage fields of the DCOptimalPowerFlow type can be employed to store the new starting values:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"for (key, idx) in system.generator.label\n analysis.power.generator.active[idx] = generatorPower(system, flow; label = key)\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.angle[i] = flow.voltage.angle[i]\nend","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Starting-Dual-Values","page":"DC Optimal Power Flow","title":"Starting Dual Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Dual variables, often referred to as Lagrange multipliers or Kuhn-Tucker multipliers, represent the shadow prices or marginal costs associated with constraints. The assignment of initial dual values occurs when the solve! function is executed. Initially, the starting dual values are unknown, but users can access and manually set them. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.dual.balance.active[1] = 0.4\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerFlowSolutionManual","page":"DC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To establish the DC optimal power flow problem, we can utilize the dcOptimalPowerFlow function. After setting up the problem, we can use the solve! function to compute the optimal values for the active power outputs of the generators and the bus voltage angles. Also, to turn off the solver output within the REPL, we use the set_silent function before calling solve! function. Here is an example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"By executing this function, we will obtain the solution with the optimal values for the active power outputs of the generators and the bus voltage angles:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Objective-Value","page":"DC Optimal Power Flow","title":"Objective Value","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To obtain the objective value of the optimal power flow solution, we can use the objective_value function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_value(analysis.method.jump)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Dual-Variables","page":"DC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The values of the dual variables are stored in the dual field of the DCOptimalPowerFlow type. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis.method.dual.balance.active[1]","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Print-Results-in-the-REPL","page":"DC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can utilize the functions printBusData and printGeneratorData to display results. Additionally, the functions listed in the Print Constraint Data section allow users to print constraint data related to buses, branches, or generators in the desired units. For example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"@power(MW, MVAr, pu)\nprintBusConstraint(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, users can easily customize the print results for specific constraint, for example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"printBusConstraint(system, analysis; label = \"Bus 1\", header = true)\nprintBusConstraint(system, analysis; label = \"Bus 2\", footer = true)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Save-Results-to-a-File","page":"DC Optimal Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusConstraint(system, analysis, file)\nend","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Save-Results-to-a-CSV-File","page":"DC Optimal Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusConstraint(system, analysis, io; style = false)\nCSV.write(\"constraint.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Primal-and-Dual-Warm-Start","page":"DC Optimal Power Flow","title":"Primal and Dual Warm Start","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Utilizing the DCOptimalPowerFlow type and proceeding directly to the solver offers the advantage of a \"warm start\". In this scenario, the starting primal and dual values for the subsequent solving step correspond to the solution obtained from the previous step.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Primal-Variables","page":"DC Optimal Power Flow","title":"Primal Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the previous example, the following solution was obtained, representing the values of the primal variables:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Dual-Variables-2","page":"DC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"We also obtained all dual values. Here, we list only the dual variables for one type of constraint as an example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.branch.label, analysis.method.dual.flow.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Modify-Optimal-Power-Flow","page":"DC Optimal Power Flow","title":"Modify Optimal Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Now, let us introduce changes to the power system from the previous example:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", maxActive = 0.08)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Next, we want to solve this modified optimal power flow problem. If we use solve! at this point, the primal and dual starting values will be set to the previously obtained values:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"solve!(system, analysis)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As a result, we obtain a new solution:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.generator.label, analysis.power.generator.active)\nprint(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Reset-Primal-and-Dual-Values","page":"DC Optimal Power Flow","title":"Reset Primal and Dual Values","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users retain the flexibility to reset these initial primal values to their default configurations at any juncture. This can be accomplished by utilizing the active power outputs of the generators and the initial bus voltage angles extracted from the PowerSystem type, employing the startingPrimal! function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"startingPrimal!(system, analysis)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The primal starting values will now be identical to those that would be obtained if the dcOptimalPowerFlow function were executed after all the updates have been applied.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Using the startingDual! function, users can clear all dual variable values, resetting them to their default state:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"startingDual!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#DCOptimalPowerAnalysisManual","page":"DC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution from the DC optimal power flow, we can calculate powers related to buses and branches using the power! function. For instance, let us consider the power system for which we obtained the DC optimal power flow solution:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid, JuMP # hide\nusing HiGHS\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, minFromBus = -0.12, maxFromBus = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, maxActive = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, maxActive = 0.2)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8])\n\nanalysis = dcOptimalPowerFlow(system, HiGHS.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Now we can calculate the active powers using the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Finally, to display the active power injections and from-bus active power flows, we can use the following code:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.power.from.active)","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nTo better understand the powers associated with buses and branches that are calculated by the power! function, we suggest referring to the tutorials on DC Optimal Power Flow.","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Print-Results-in-the-REPL-2","page":"DC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus data with the desired units, users can use the following function:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nprintBusData(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Injection","page":"DC Optimal Power Flow","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = injectionPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Injection-from-Generators","page":"DC Optimal Power Flow","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = supplyPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"manual/dcOptimalPowerFlow/#Active-Power-Flow","page":"DC Optimal Power Flow","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"active = fromPower(system, analysis; label = \"Branch 2\")\nactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/powerSystemModel/#PowerSystemModelManual","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid supports the type PowerSystem to preserve power system data, with the following fields: bus, branch, generator, base, and model. The bus, branch, and generator fields hold data related to buses, branches, and generators, respectively. The base field stores base values for power and voltages, with the default being three-phase power measured in volt-amperes for the base power and line-to-line voltages measured in volts for base voltages. Within the model field, the ac and dc subfields store vectors and matrices pertinent to the power system's topology and parameters, and these are utilized in either the AC or DC framework.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The type PowerSystem can be created using a function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid supports three modes for populating the PowerSystem type: using built-in functions, using HDF5 file format, and using Matpower case files.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is recommended to use the HDF5 format for large-scale systems. To facilitate this, JuliaGrid has the function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"savePowerSystem.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Upon creation of the PowerSystem type, users can generate vectors and matrices based on the power system topology and parameters using the following functions:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"acModel!,\ndcModel!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once the PowerSystem type is created, users can add buses, branches, generators, or manage costs associated with the output powers of the generators, using the following functions:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!,\naddBranch!,\naddGenerator!,\ncost!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"JuliaGrid also provides macros @bus, @branch, and @generator to define templates that aid in creating buses, branches, and generators. These templates help avoid entering the same parameters repeatedly.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, it is feasible to modify the parameters of buses, branches, and generators. When these functions are executed, all relevant fields within the PowerSystem type will be automatically updated, encompassing the ac and dc fields as well. These functions include:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBus!,\nupdateBranch!,\nupdateGenerator!.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nThe functions addBranch!, addGenerator!, updateBus!, updateBranch!, updateGenerator!, and cost! serve a dual purpose. While their primary function is to modify the PowerSystem type, they are also designed to accept various analysis models like AC or DC power flow models. When feasible, these functions not only modify the PowerSystem type but also adapt the analysis model, often resulting in improved computational efficiency. Detailed instructions on utilizing this feature can be found in dedicated manuals for specific analyses.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#BuildModelManual","page":"Power System Model","title":"Build Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The powerSystem function generates the PowerSystem type and requires a string-formatted path to either Matpower cases or HDF5 files as input. Alternatively, the PowerSystem can be created without any initial data by initializing it as empty, allowing the user to construct the power system from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Matpower-File","page":"Power System Model","title":"Matpower File","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For example, to create the PowerSystem type using the Matpower case file for the IEEE 14-bus test case, which is named case14.m and located in the folder C:\\matpower, the following Julia code can be used:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem(\"C:/matpower/case14.m\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#HDF5-File","page":"Power System Model","title":"HDF5 File","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In order to use the HDF5 file as input to create the PowerSystem type, it is necessary to have saved the data using the savePowerSystem function beforehand. As an example, let us say we saved the power system as case14.h5 in the directory C:\\hdf5. In this case, the following Julia code can be used to construct the PowerSystem type:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem(\"C:/hdf5/case14.h5\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIt is recommended to load the power system from the HDF5 file to reduce the loading time.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Model-from-Scratch","page":"Power System Model","title":"Model from Scratch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Alternatively, the model can be built from scratch using built-in functions, for example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, base = 345e3)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, base = 345e3)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Internal-Unit-System","page":"Power System Model","title":"Internal Unit System","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The PowerSystem type stores all electrical quantities in per-units and radians, except for the base values of power and voltages. The base power value is expressed in volt-amperes, while the base voltages are given in volts.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Change-Base-Unit-Prefixes","page":"Power System Model","title":"Change Base Unit Prefixes","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The user can retrieve the base power and base voltage values along with their respective units:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.power.value, system.base.power.unit\nsystem.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"By using the @base macro, users can change the prefixes of the base units. For instance, if users wish to convert base power and base voltage values to megavolt-amperes (MVA) and kilovolts (kV) respectively, they can execute the following macro:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@base(system, MVA, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After executing the macro, the base power and voltage values and their units will be modified accordingly:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.power.value, system.base.power.unit\nsystem.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#SaveModelManual","page":"Power System Model","title":"Save Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once the PowerSystem type has been created using one of the methods outlined in Build Model, the data can be stored in the HDF5 file by using the savePowerSystem function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"savePowerSystem(system; path = \"C:/matpower/case14.h5\", reference = \"IEEE 14-bus test case\")","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"All electrical quantities saved in the HDF5 file are in per-units and radians, except for base values for power and voltages, which are given in volt-amperes and volts. Note that even if the user modifies the base units using the @base macro, the units will still be saved with the default settings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddBusManual","page":"Power System Model","title":"Add Bus","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The buses can be added both to the loaded power system, or to the one created from scratch. As an illustration, we can initiate the PowerSystem type and then incorporate two buses by utilizing the addBus! function:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, base = 345e3)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.034907, base = 345e3)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this case, we have created two buses where the active power demanded by the consumer at Bus 1 is specified in per-units, which are the same units used to store electrical quantities:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.demand.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is worth noting that the base keyword is used to specify the base voltages, and its default input unit is in volts (V):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Also, we have defined the bus voltage angle in radians for Bus 2 as its initial value:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.voltage.angle","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nWe recommend reading the documentation for the addBus! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Typically, all keywords associated with electrical quantities are expected to be provided in per-units (pu) and radians (rad) by default, with the exception of base voltages, which should be specified in volts (V). However, users can choose to use different units than the default per-units and radians or modify the prefix of the base voltage unit by using macros such as the following:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\n@power(MW, MVAr, pu)\n@voltage(pu, deg, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This practical example showcases the customization approach. For keywords tied to active powers, the unit is set as megawatts (MW), while reactive powers employ megavolt-amperes reactive (MVAr). Apparent power, on the other hand, employs per-units (pu). As for keywords concerning voltage magnitude, per-units (pu) remain the choice, but voltage angle mandates degrees (deg). Lastly, the input unit for base voltage is elected to be kilovolts (kV).","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now we can create identical two buses as before using new system of units as follows:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 10.0, base = 345.0)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -2.0, base = 345.0)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As can be observed, electrical quantities will continue to be stored in per-units and radians format:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[system.bus.demand.active system.bus.voltage.angle]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The base voltage values will still be stored in volts (V) since we only changed the input unit prefix, and did not modify the internal unit prefix, as shown below:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To modify the internal unit prefix, the following macro can be used:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@base(system, VA, kV)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After executing this macro, the base voltage values will be stored in kilovolts (kV):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.base.voltage.value, system.base.voltage.unit","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddBranchManual","page":"Power System Model","title":"Add Branch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The branch connecting two buses can be added once those buses are defined, and from and to keywords must correspond to labels of those buses. For example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Here, we created the branch from Bus 1 to Bus 2 with following parameter:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is recommended to consult the documentation for the addBranch! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-2","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To use units other than per-units (pu) and radians (rad), macros can be employed to change the input units. For example, if there is a need to use ohms (Ω), the macros below can be employed:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@parameter(Ω, pu)\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, angle = -0.2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 22.8528)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Still, all electrical quantities are stored in per-units, and the same branch as before is created:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"It is important to note that, when working with impedance and admittance values in ohms (Ω) and siemens (S) that are related to a transformer, the assignment must be based on the primary side of the transformer.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddGeneratorManual","page":"Power System Model","title":"Add Generator","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The generator connected to a bus can be added once the bus is defined. Each generator must have a unique label, and the bus keyword should correspond to the unique label of the bus it is connected to. For instance:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 2\", active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the above code, we add the generator to the Bus 2, with active and reactive power outputs set to:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.output.active, system.generator.output.reactive","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similar to buses and branches, the input units can be changed to units other than per-units using different macros.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is recommended to refer to the documentation for the addGenerator! function, where we have provided a list of all the keywords that can be used.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddTemplatesManual","page":"Power System Model","title":"Add Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The functions addBus!, addBranch!, and addGenerator! are used to add bus, branch, and generator to the power system, respectively. If certain keywords are not specified, default values are assigned to some parameters.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Default-Keyword-Values","page":"Power System Model","title":"Default Keyword Values","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Regarding the addBus! function, the bus type is automatically configured as a demand bus with type = 1. The initial bus voltage magnitude is set to magnitude = 1.0 per-unit, while the base voltage is established as base = 138e3 volts. Additionally, the minimum and maximum bus voltage magnitudes are set to minMagnitude = 0.9 per-unit and maxMagnitude = 1.1 per-unit, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Transitioning to the addBranch! function, the default operational status is status = 1, indicating that the branch is in-service. The off-nominal turns ratio for the transformer is specified as turnsRatio = 1.0, and the phase shift angle is set to shiftAngle = 0.0, collectively defining the line configuration with these standard settings. The flow rating is also configured as type = 1. Moreover, the minimum and maximum voltage angle differences between the from-bus and to-bus ends are set to minDiffAngle = -2pi and maxDiffAngle = 2pi, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, the addGenerator! function designates an operational generator by employing status = 1, and it sets magnitude = 1.0 per-unit, denoting the desired voltage magnitude setpoint.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The remaining parameters are initialized with default values of zero.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Change-Default-Keyword-Values","page":"Power System Model","title":"Change Default Keyword Values","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In JuliaGrid, users have the flexibility to adjust default values and assign customized values using the @bus, @branch, and @generator macros. These macros create bus, branch, and generator templates that are used every time the addBus!, addBranch!, and addGenerator! functions are called. For instance, the code block shows an example of creating bus, branch, and generator templates with customized default values:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\n@bus(type = 2, active = 0.1)\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.5)\n\n@branch(reactance = 0.12)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\")\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.06)\n\n@generator(magnitude = 1.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.6)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This code example involves two uses of the addBus! and addBranch! functions. In the first use, the functions rely on the default values set by the templates created with the @bus and @branch macros. In contrast, the second use passes specific values that match the keywords used in the templates. As a result, the templates are ignored:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.layout.type\nsystem.bus.demand.active\nsystem.branch.parameter.reactance","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the given example, the @generator macro is utilized instead of repeatedly specifying the magnitude keyword in the addGenerator! function. This macro creates a generator template with a default value for magnitude, which is automatically applied every time the addGenerator! function is called. Therefore, it eliminates the requirement to set the magnitude value for each individual generator:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.voltage.magnitude","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-3","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Templates can also be defined using a custom unit system, for example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\n@power(MW, MVAr, MVA)\n@bus(active = 100, reactive = 200)\naddBus!(system; label = \"Bus 1\")\n\n@power(pu, pu, pu)\naddBus!(system; label = \"Bus 2\", active = 0.5)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, we create the bus template and one bus using SI power units, and then we switch to per-units and add the second bus. It is important to note that once the template is defined in any unit system, it remains valid regardless of subsequent unit system changes. The resulting power values are:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.demand.active\nsystem.bus.demand.reactive","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Thus, JuliaGrid automatically tracks the unit system used to create templates and provides the appropriate conversion to per-units and radians. Even if the user switches to a different unit system later on, the previously defined template will still be valid.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Multiple-Templates","page":"Power System Model","title":"Multiple Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In the case of calling the @bus, @branch, or @generator macros multiple times, the provided keywords and values will be combined into a single template for the corresponding component (bus, branch, or generator), which will be used for generating the component.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Reset-Templates","page":"Power System Model","title":"Reset Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To reset the bus, branch, and generator templates to their default settings, users can utilize the following macros:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@default(bus)\n@default(branch)\n@default(generator)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Additionally, users can reset all templates using the macro:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@default(template)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#LabelsManual","page":"Power System Model","title":"Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we have shown, JuliaGrid mandates a distinctive label for every bus, branch, or generator. These labels are stored in ordered dictionaries, functioning as pairs of strings and integers. The string signifies the exclusive label for the specific component, whereas the integer maintains an internal numbering of buses, branches, or generators.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nString labels improve readability, but in larger models, the overhead from using strings can become substantial. To reduce memory usage, users can configure ordered dictionaries to accept and store integers as labels:@labels(Integer)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Integer-Based-Labeling","page":"Power System Model","title":"Integer-Based Labeling","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us take a look at the following illustration:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.1)\naddBus!(system; label = 2, type = 1, angle = -0.2)\n\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.12)\n\naddGenerator!(system; label = 1, bus = 2, active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, we use the macro @labels to specify that labels will be stored as integers. It is essential to run this macro; otherwise, even if integers are used in subsequent functions, they will be stored as strings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Here, two buses are created with labels 1 and 2. A branch connects these two buses, assigned a unique label of 1. Finally, a generator is connected to bus 2, with its own label set to 1.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Automated-Labeling","page":"Power System Model","title":"Automated Labeling","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Users also possess the option to omit the label keyword, allowing JuliaGrid to independently allocate unique labels for buses, branches, or generators. In such instances, JuliaGrid employs an ordered set of incremental integers for labeling components. To illustrate, consider the subsequent example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; type = 3, active = 0.1)\naddBus!(system; type = 1, angle = -0.2)\n\naddBranch!(system; from = 1, to = 2, reactance = 0.12)\n\naddGenerator!(system; bus = 2, active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This example models the same power system as before. In the previous case, we manually assigned labels using incremental integers. Here, we rely on the automatic labeling behavior, but since the macro @labels is not used, the labels will be stored as strings.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Automated-Labeling-Using-Templates","page":"Power System Model","title":"Automated Labeling Using Templates","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Additionally, users have the ability to generate labels through templates and employ the symbol ? to insert an incremental set of integers at any location. For instance:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\n@bus(label = \"Bus ? HV\")\naddBus!(system; type = 3, active = 0.1)\naddBus!(system; type = 1, angle = -0.2)\n\n@branch(label = \"Branch ?\")\naddBranch!(system; from = \"Bus 1 HV\", to = \"Bus 2 HV\", reactance = 0.12)\n\n@generator(label = \"Generator ?\")\naddGenerator!(system; bus = \"Bus 2 HV\", active = 0.5, reactive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In this example, two buses are generated and labeled as Bus 1 HV and Bus 2 HV, along with one branch and one generator labeled as Branch 1 and Generator 1, respectively.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Retrieving-Labels","page":"Power System Model","title":"Retrieving Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Finally, we will outline how users can retrieve stored labels. Let us consider the following power system creation:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 2\")\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 3\")\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 1\", reactance = 0.8)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\")\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 3\")\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For instance, the bus labels can be accessed using the variable:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.label","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"If the objective is to obtain only labels, users can utilize the following:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"label = collect(keys(system.bus.label))","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"This approach can also be extended to branch and generator labels by making use of the variables present within the PowerSystem type, namely system.branch.label or system.generator.label.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Moreover, the from and to keywords associated with branches are stored based on internally assigned numerical values linked to bus labels. These values are stored in variables:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[system.branch.layout.from system.branch.layout.to]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To recover the original from and to labels, we can utilize:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"[label[system.branch.layout.from] label[system.branch.layout.to]]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, the bus keywords related to generators are saved based on internally assigned numerical values corresponding to bus labels and can be accessed using:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.layout.bus","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To recover the original bus labels, we can utilize:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"label[system.generator.layout.bus]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nJuliaGrid offers the capability to print labels alongside various types of data, such as power system parameters, voltages, powers, currents, or constraints used in optimal power flow analyses. For instance:print(system.branch.label, system.branch.parameter.reactance)","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Loading-and-Saving-Labels","page":"Power System Model","title":"Loading and Saving Labels","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When a user loads a power system from a Matpower file, the default behavior is to store labels as strings. However, this can be overridden by using the @labels macro to store labels as integers.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When saving the power system to an HDF5 file, the label type (strings or integers) will match the type chosen during system setup. Likewise, when loading data from an HDF5 file, the label type will be preserved as saved, regardless of what is set by the @labels macro.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#ACDCModelManual","page":"Power System Model","title":"AC and DC Model","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"When we constructed the power system, we can create an AC and/or DC model, which include vectors and matrices related to the power system's topology and parameters. The following code snippet demonstrates this:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", resistance = 0.008, reactance = 0.05)\n\nacModel!(system)\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIn many instances throughout the JuliaGrid documentation, we explicitly mention these functions by their names, although it is not mandatory. If a user begins any of the various AC or DC analyses without having previously established the AC or DC model using the acModel! or dcModel! function, the respective function for setting the analysis will automatically create the AC or DC model.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The nodal matrices are one of the components of both the AC and DC models and are stored in the variables:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix\nsystem.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nThe AC model is used for performing AC power flow, AC optimal power flow, AC state estimation, or state estimation with PMUs, whereas the DC model is essential for various DC or linear analyses. Consequently, once these models are developed, they can be applied to various types of simulations. We recommend that the reader refers to the tutorial on AC and DC models.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#New-Branch-Triggers-Model-Update","page":"Power System Model","title":"New Branch Triggers Model Update","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can execute the acModel! and dcModel! functions after defining the final number of buses, and each new branch added will trigger an update of the AC and DC matrices and vectors. Here is an example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\nacModel!(system)\ndcModel!(system)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; from = \"Bus 2\", to = \"Bus 3\", resistance = 0.008, reactance = 0.05)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For example, the nodal matrix in the DC framework has the same values as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nIt is not fully recommended to create AC and DC models before adding a large number of branches if the execution time of functions is important. Instead, triggering updates to the AC and DC models using the addBranch! function is useful for power systems that require the addition of several branches. This update avoids the need to recreate vectors and matrices from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#New-Bus-Triggers-Model-Erasure","page":"Power System Model","title":"New Bus Triggers Model Erasure","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The AC and DC models must be defined once a finite number of buses has been defined, otherwise, adding a new bus will delete them. For example, if we attempt to add a new bus to the PowerSystem type that was previously created, the current AC and DC models will be completely erased:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!(system; label = \"Bus 4\", type = 2)\nsystem.model.ac.nodalMatrix\nsystem.model.dc.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateBusManual","page":"Power System Model","title":"Update Bus","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once a bus has been added to the PowerSystem type, users have the flexibility to modify all parameters defined within the addBus! function. This means that when the updateBus! function is used, the PowerSystem type within AC and DC models that have been created is updated. This eliminates the need to recreate the AC and DC models from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To illustrate, let us consider the following power system:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, conductance = 0.01)\naddBus!(system; label = \"Bus 2\", type = 2, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, susceptance = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 1\", active = 0.2)\n\nacModel!(system)\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For instance, the nodal matrix in the AC framework has the following form:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now, let us add a shunt element to Bus 2:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBus!(system; label = \"Bus 2\", conductance = 0.4, susceptance = 0.5)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we can observe, executing the function triggers an update of the AC nodal matrix:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateBranchManual","page":"Power System Model","title":"Update Branch","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Once a branch has been added to the PowerSystem type, users have the flexibility to modify all parameters defined within the addBranch! function. This means that when the updateBranch! function is used, the PowerSystem type within AC and DC models that have been created is updated. This eliminates the need to recreate the AC and DC models from scratch.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To illustrate, let us continue with the previous example and modify the parameters of Branch 1 as follows:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBranch!(system; label = \"Branch 1\", resistance = 0.012, reactance = 0.3)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can observe the update in the AC nodal matrix:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Next, let us switch the status of Branch 2 from in-service to out-of-service:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateBranch!(system; label = \"Branch 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As before, the updated AC nodal matrix takes the following form:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.model.ac.nodalMatrix","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Drop-Zeros","page":"Power System Model","title":"Drop Zeros","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After the last execution of the updateBranch! function, the nodal matrices will contain zeros, as demonstrated in the code example. If needed, the user can remove these zeros using the dropZeros! function, as shown below:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"dropZeros!(system.model.ac)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"note: Info\nIt is worth mentioning that in simulations conducted with the JuliaGrid package, the precision of the outcomes remains unaffected even if zero entries are retained. However, we recommend users utilize this function instead of dropzeros! from the SuiteSparse package to ensure seamless functioning of all JuliaGrid functionalities.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#UpdateGeneratorManual","page":"Power System Model","title":"Update Generator","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Finally, users can update all generator parameters defined within the addGenerator! function using the updateGenerator! function. The execution of this function will affect all variables within the PowerSystem type.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In short, in addition to the generator field, JuliaGrid also retains variables associated with generators within the bus field. As an example, let us examine one of these variables and its values derived from a previous example:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.supply.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Next, we will change the active output power of Generator 1:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"updateGenerator!(system; label = \"Generator 1\", active = 0.9)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"As we can see, executing the function triggers an update of the observed variable:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.bus.supply.active","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Hence, this function ensures the adjustment of generator parameters and updates all fields of the PowerSystem type affected by them.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#AddUpdateCostsManual","page":"Power System Model","title":"Add and Update Costs","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The cost! function is responsible for adding and updating costs associated with the active or reactive power produced by the corresponding generator. These costs are added only if the corresponding generator is defined.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To start, let us create an example of a power system using the following code:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 2\")\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Polynomial-Cost","page":"Power System Model","title":"Polynomial Cost","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Let us define a quadratic polynomial cost function for the active power produced by the Generator 1:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.0; 500.0; 150.0])","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"In essence, what we have accomplished is the establishment of a cost function depicted as f(P_textg1) = 1100 P_textg1^2 + 500 P_textg1 + 150 through the code provided. In general, when constructing a polynomial cost function, the coefficients must be ordered from the highest degree to the lowest.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The default input units are in per-units (pu), with coefficients of the cost function having units of currency/pu²-hr for 1100, currency/pu-hr for 500, and currency/hr for 150. Therefore, the coefficients are stored exactly as entered:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.active.polynomial[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"By setting active = 2 within the function, we express our intent to specify the active power cost using the active key. By using a value of 2, we signify our preference for employing a polynomial cost model for the associated generator. This flexibility is neccessary when we have also previously defined a piecewise linear cost function for the same generator. In such cases, we can set active = 1 to utilize the piecewise linear cost function to represent the cost of the corresponding generators. Thus, we retain the freedom to choose between these two cost functions according to the requirements of our simulation. Additionally, users have the option to define both piecewise and polynomial costs within a single function call, further enhancing the versatility of the implementation.","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Piecewise-Linear-Cost","page":"Power System Model","title":"Piecewise Linear Cost","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"We can also create a piecewise linear cost function, for example, let us create the reactive power cost function for the same generator using the following code:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", reactive = 1, piecewise = [0.11 12.3; 0.15 16.8])\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"The first column denotes the generator's output reactive powers in per-units, while the second column specifies the corresponding costs for the specified reactive power in currency/hr. Thus, the data is stored exactly as entered:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.reactive.piecewise[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"manual/powerSystemModel/#Customizing-Input-Units-for-Keywords-4","page":"Power System Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Changing input units from per-units (pu) can be particularly useful since cost functions are usually related to SI units. Let us set active powers in megawatts (MW) and reactive powers in megavolt-amperes reactive (MVAr):","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"@power(MW, MVAr, pu)\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Now, we can add the quadratic polynomial function using megawatts:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", active = 2, polynomial = [0.11; 5.0; 150.0])","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"After inspecting the resulting cost data, we can see that it is the same as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.active.polynomial[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Similarly, we can define the linear piecewise cost using megavolt-amperes reactive:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"cost!(system; label = \"Generator 1\", reactive = 1, piecewise = [11.0 12.3; 15.0 16.8])\nnothing # hide","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"Upon inspection, we can see that the stored data is the same as before:","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"system.generator.cost.reactive.piecewise[1]","category":"page"},{"location":"manual/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"tip: Tip\nThe cost! function not only adds costs but also allows users to update previously defined cost functions. This functionality is particularly valuable in optimal power flow analyses, as it allows users to modify generator power costs without the need to recreate models from scratch.","category":"page"},{"location":"background/installation/#InstallationGuide","page":"Installation Guide","title":"Installation Guide","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"JuliaGrid is compatible with Julia version 1.9 and later. To get started with JuliaGrid, users should first install Julia and consider using a code editor for a smoother coding experience.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-Julia","page":"Installation Guide","title":"Install Julia","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"Begin by downloading and installing Julia. We can choose either the Current Stable Release or the Long-term Support Release.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"The Current Stable Release is the most recent version of Julia, providing access to the latest features and typically offering better performance. For most users, we recommend installing the Current Stable Release. The Long-term Support Release is an older version of Julia that has continued to receive bug and security fixes. However, it may not have the latest features or performance improvements.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-Code-Editor","page":"Installation Guide","title":"Install Code Editor","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"For a smoother development experience, we recommend using a code editor. While you can write Julia code in any text editor, using an integrated development environment (IDE) makes coding easier and more efficient. We suggest installing Visual Studio Code, which provides excellent support for Julia through its dedicated Julia extension. Visual Studio Code offers features like syntax highlighting, debugging, and autocompletion, making it an ideal choice for both beginners and experienced users.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"The Julia extension for Visual Studio Code includes built-in dynamic autocompletion, inline results, plot pane, integrated REPL, variable view, code navigation, and many other advanced language features. For a step-by-step guide on how to use Julia in Visual Studio Code, you can follow the tutorial available here.","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"","category":"page"},{"location":"background/installation/#Install-JuliaGrid","page":"Installation Guide","title":"Install JuliaGrid","text":"","category":"section"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"To get the JuliaGrid package installed, execute the following Julia command:","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"import Pkg\nPkg.add(\"JuliaGrid\")","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"When a new version of JuliaGrid is released, you can update it with the following command:","category":"page"},{"location":"background/installation/","page":"Installation Guide","title":"Installation Guide","text":"import Pkg\nPkg.update(\"JuliaGrid\")","category":"page"},{"location":"tutorials/perunit/#PerUnitSystem","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"In power system modeling and analysis, variables and parameters are often normalized using the per-unit system. The per-unit system is particularly advantageous for analyzing networks with multiple voltage levels connected by transformers with different turns ratios.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"In static scenarios, there are four key quantities of interest: voltage, current, power, and impedance or admittance. Defining a per-unit system requires selecting base values for each of these quantities. However, since these quantities are interconnected by various laws, the choice of base values cannot be arbitrary. Typically, the base quantities are chosen as voltage and power, with the base current and impedance (or admittance) then calculated accordingly. Usually, base quantities are selected as follows:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"three-phase apparent power S_3phi(textb),\nline-to-line voltage V_LL(textb).","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"While the value of three-phase apparent power is unique across the entire system, multiple line-to-line base voltages are used to account for the different voltage zones created by transformers.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nSince balanced three-phase power systems are treated as a single line with a neutral return, confusion may arise regarding the relationship between the per-unit values of line voltages and phase voltages, as well as between the per-unit values of single-phase and three-phase powers [7]. To clarify these relationships, we will systematically explore the conversions between the per-unit and SI systems below.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Powers","page":"Per-Unit System","title":"Powers","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Let us consider the three-phase apparent power expressed in SI units, denoted as S_3phi(textsi). To convert this into the per-unit system, we divide it by the base power:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"S_3phi(textpu) = cfracS_3phi(textsi)S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Now, let us examine the power of a single phase and convert it to the per-unit system:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"S_1phi(textpu) = cfracS_1phi(textsi)S_1phi(textb) = cfracS_3phi(textsi)3 cfrac3S_3phi(textb) = cfracS_3phi(textsi)S_3phi(textb) = S_3phi(textpu)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"This indicates that in the per-unit system, there is no distinction between three-phase and single-phase powers. The type of power only becomes relevant when converting back from per-unit to SI units, and vice versa.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nAs is standard practice, even if all simulations utilize a single-phase equivalent, input powers provided in SI units are assumed to represent three-phase powers. Similarly, if simulation results are displayed in SI units, they are considered to be three-phase powers, as we have selected three-phase power as the base value.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Voltages","page":"Per-Unit System","title":"Voltages","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Format for input data that JuliaGrid uses required value for base voltage per each bus, and those values represent the line-to-line voltages. On the other hand, in all analyses we are working with line-to-neutral voltages. To convert a line-to-neutral voltage given in SI units V_LN(textsi) to per-unit form V_LN(textpu), or vice versa, we use the formula:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"V_LN(textpu) = cfracsqrt3V_LN(textsi)V_LL(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nSimilarly to power, JuliaGrid simulations use a single-phase equivalent. Voltage values specified in volts correspond to line-to-neutral values, while base voltages are expected to be provided as line-to-line values.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Impedances","page":"Per-Unit System","title":"Impedances","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Let us first consider the line itself, excluding transformers. The base impedance of the line is given by:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_L(textb) = cfracV_LL(textb)^2S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"If the impedance is provided in ohms, its value in the per-unit system is:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_L(textpu) = cfracZ_L(textsi)Z_L(textb) = cfracZ_L(textsi) S_3phi(textb)V_LL(textb)^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"A common question that arises is which base voltage should be used for the line, considering the two ends of the line (from-bus and to-bus). The key assumption here is that the base voltages correspond to the nominal voltages of the transformers. Therefore, when the user defines base voltages, JuliaGrid assumes these voltages represent the nominal voltages of the transformers, implying that the base voltages on both the from-bus and to-bus ends of the line will be the same.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Now, let us consider the transformer. The base voltages at the from-bus end (primary side) V_LLF(textb), and the to-bus end (secondary side) V_LLT(textb), will generally be different. This requires us to define a conversion method for impedance. Typically, when impedance is given in ohms, it refers to the primary side of the transformer, denoted as Z_F(textsi), while the impedance in our unified branch model refers to the secondary side, denoted as Z_T(textsi). To convert the impedance from the from-bus end to the to-bus end, we use:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textsi) = cfracZ_F(textsi)m^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"where m is the effective turns ratio, calculated as:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"m = tau cfracV_LLF(textb)V_LLT(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"with tau is off-nominal turns ratio. This equation provides the impedance on the to-bus end of the branch or the secondary side of the transformer in ohms.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"To convert this impedance to the per-unit system, we use the base impedance for the secondary side:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textpu) = cfracZ_T(textsi)Z_T(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"where:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textb) = cfracV_LLT(textb)^2S_3phi(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Substituting the previous expressions, we obtain the following formula for the impedance on the secondary side in per-unit system:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Z_T(textpu) = cfracZ_F(textsi) S_3phi(textb)tau^2 V_LLF(textb)^2","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"This formula applies to both lines and transformers. For a line, where tau = 1, the formula simplifies and becomes the same as the impedance equation for a line.","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"note: Info\nIn the case of a transformer, if impedances or admittances are provided in SI units, they must be specified for the primary side (from-bus end).","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"","category":"page"},{"location":"tutorials/perunit/#Currents","page":"Per-Unit System","title":"Currents","text":"","category":"section"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"Once the base power and base voltage values are set, we can calculate the base current flowing through a line or branch as follows:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"I_L(textb) = cfracS_3phi(textb)sqrt3V_LL(textb)","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"When we transform currents that are given in SI unit to per-unit, or vice versa, we use the following formula:","category":"page"},{"location":"tutorials/perunit/","page":"Per-Unit System","title":"Per-Unit System","text":"I_L(textpu) = cfracI_L(textsi)I_L(textb) = cfracsqrt3I_L(textsi)V_LL(textb)S_3phi(textb)","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUStateEstimationTutorials","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the AC model:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of PMUs mathcalM equiv barmathcalP into the graph mathcalG, that capture both bus voltage and branch current phasors. To construct the linear PMU state estimation model, we represent the vector of state variables, as well as phasor measurements, in the rectangular coordinate system. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEModelTutorials","page":"PMU State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Initially, PMUs output phasor measurements in polar coordinates. However, these measurements can be interpreted in rectangular coordinates, where the real and imaginary parts of bus voltages and branch current phasors serve as measurements. Additionally, to obtain the linear system of equations, we observe a vector of state variables in rectangular coordinates mathbf x equivmathbfV_textremathbfV_textim:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"mathbfV_mathrmre =bigRe(barV_1)dotsRe(barV_n)big^T, representing the real parts of complex bus voltages,\nmathbfV_mathrmim =bigIm(barV_1)dotsIm(barV_n)big^T, representing the imaginary parts of complex bus voltages.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, the total number of state variables is 2n. It is worth noting that in this approach to state estimation, we do not require the slack bus.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The primary drawback of this method stems from measurement errors, which are associated with polar coordinates. Consequently, the covariance matrix must be transformed from polar to rectangular coordinates. As a result, errors from a single PMU are correlated, leading to a non-diagonal covariance matrix. Despite this, the covariance matrix is commonly treated as diagonal, impacting the state estimation accuracy in such scenarios.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, the model includes real and imaginary parts of bus voltage and current phasor measurements from the set mathcalM, contributing to the formulation of a linear system of equations:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbfh(mathbf x)= h_1(mathbf x), dots, h_k(mathbf x)^T represents the vector of linear measurement functions, where k = 2barmathcalP is the number of measurement functions, mathbfz = z_1dotsz_k^T denotes the vector of measurement values, and mathbfu = u_1dotsu_k^T represents the vector of measurement errors.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"These errors are assumed to follow a Gaussian distribution with a zero mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In summary, upon defining the PMU, each i-th PMU is associated with two measurement functions h_2i-1(mathbf x), h_2i(mathbf x), along with their respective measurement values z_2i-1, z_2i, as well as their variances v_2i-1, v_2i, and possibly covariances w_2i-1, w_2i.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Bus-Voltage-Phasor-Measurements","page":"PMU State Estimation","title":"Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"When a PMU (V_i theta_i) in barmathcalP is introduced at bus i in mathcalN in this type of state estimation, users specify the measurement values, variances, and measurement functions of vectors as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barV_i) z_Im(barV_i) mathbfv = v_Re(barV_i) v_Im(barV_i) mathbfh(mathbf x) = h_Re(barV_i)(mathbf x) h_Im(barV_i)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"V₂, θ₂\", bus = 2, magnitude = 0.9, angle = -0.1,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barV_i) = z_V_i cos z_theta_i\n z_Im(barV_i) = z_V_i sin z_theta_i\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)right^2 =\n v_V_i (cos z_theta_i)^2 + v_theta_i (z_V_i sin z_theta_i)^2\n v_Im(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)right^2 =\n v_V_i (sin z_theta_i)^2 + v_theta_i (z_V_i cos z_theta_i)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Lastly, the functions defining the bus voltage phasor measurement are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barV_i)(mathbf x) = Re(barV_i)\n h_Im(barV_i)(mathbf x) = Im(barV_i)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" cfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial Re(barV_i)=1 \n cfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial Im(barV_i)=1","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the previous example, the user neglected the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barV_i) w_Im(barV_i)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"V₃, θ₃\", bus = 3, magnitude = 0.9, angle = -0.2,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) =\n v_V_i cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) +\n v_theta_i cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"which results in the solution:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) = cos z_theta_i sin z_theta_i(v_V_i - v_theta_i z_V_i^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#From-Bus-End-Current-Phasor-Measurements","page":"PMU State Estimation","title":"From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the user chooses to include phasor measurement (I_ij psi_ij) in barmathcalP in the state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barI_ij) z_Im(barI_ij) mathbfv = v_Re(barI_ij) v_Im(barI_ij) mathbfh(mathbf x) = h_Re(barI_ij)(mathbf x) h_Im(barI_ij)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₂₃, ψ₂₃\", from = 3, magnitude = 0.3, angle = 0.4,\nvarianceMagnitude = 1e-3, varianceAngle = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barI_ij) = z_I_ij cos z_psi_ij\n z_Im(barI_ij) = z_I_ij sin z_psi_ij\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barI_ij) = v_I_ij (cos z_psi_ij)^2 + v_psi_ij (z_I_ij sin z_psi_ij)^2 \n v_Im(barI_ij) = v_I_ij (sin z_psi_ij)^2 + v_psi_ij (z_I_ij cos z_psi_ij)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The functions defining the current phasor measurement at the from-bus end are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barI_ij)(mathbf x) = A Re(barV_i) - B Im(barV_i) - left(C cosphi_ij - D sin phi_ijright) Re(barV_j) + left(Csin phi_ij + Dcos phi_ij right) Im(barV_j) \n h_Im(barI_ij)(mathbf x) = B Re(barV_i) + A Im(barV_i) - left(C sin phi_ij + D cosphi_ijright) Re(barV_j) - left(Ccos phi_ij - Dsin phi_ij right)Im(barV_j)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n A = cfracg_ij + g_textsijtau_ij^2\n B = cfracb_ij+b_textsij tau_ij^2\n C = cfracg_ijtau_ij\n D = cfracb_ijtau_ij\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Re(barV_i) =\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial Im(barV_i) = A \n cfracmathrm partialh_Re(barI_ij)(mathbf x) mathrm partial Re(barV_j) =\n cfracmathrm partialh_Im(barI_ij)(mathbf x) mathrm partial Im(barV_j) =\n - left(C cosphi_ij - D sin phi_ijright)\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Im(barV_i) =-\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial Re(barV_i) =\n -B \n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial Im(barV_j) = -\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partialRe(barV_j) =\n left(Csin phi_ij + D cos phi_ij right)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barI_ij) w_Im(barI_ij)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₁₃, ψ₁₃\", from = 2, magnitude = 0.3, angle = -0.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barI_ij) = w_Im(barI_ij) = sin z_psi_ij cos z_psi_ij(v_I_ij - v_psi_ij z_I_ij^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#To-Bus-End-Current-Phasor-Measurements","page":"PMU State Estimation","title":"To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the user chooses to include phasor measurement (I_ji psi_ji) in barmathcalP in the state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz = z_Re(barI_ji) z_Im(barI_ji) mathbfv = v_Re(barI_ji) v_Im(barI_ji) mathbfh(mathbf x) = h_Re(barI_ji)(mathbf x) h_Im(barI_ji)(mathbf x)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₃₂, ψ₃₂\", to = 3, magnitude = 0.3, angle = -2.9,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n z_Re(barI_ji) = z_I_ji cos z_psi_ji\n z_Im(barI_ji) = z_I_ji sin z_psi_ji\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The variances can be calculated as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n v_Re(barI_ji) = v_I_ji (cos z_psi_ji)^2 + v_psi_ji (z_I_ji sin z_psi_ji)^2 \n v_Im(barI_ji) = v_I_ji (sin z_psi_ji)^2 + v_psi_ji (z_I_ji cos z_psi_ji)^2\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The functions defining the current phasor measurement at the to-bus end are:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n h_Re(barI_ji)(mathbf x) = tau_ij^2 A Re(barV_j) - tau_ij^2 B Im(barV_j) - left(C cosphi_ij + D sin phi_ijright) Re(barV_i) - left( Csin phi_ij - Dcos phi_ij right) Im(barV_i)\n h_Im(barI_ji)(mathbf x) = tau_ij^2 B Re(barV_j) + tau_ij^2 A Im(barV_j) + left(C sin phi_ij - D cosphi_ij right) Re(barV_i) - left(Ccos phi_ij + Dsin phi_ijright) Im(barV_i)\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The coefficient expressions for measurement functions are as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Re(barV_i) =\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Im(barV_i) =\n - left(C cosphi_ij + D sin phi_ijright)\n cfracmathrm partialh_Re(barI_ji)(mathbf x) mathrm partial Re(barV_j) =\n cfracmathrm partialh_Im(barI_ji)(mathbf x) mathrm partial Im(barV_j) = tau_ij^2A\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Im(barV_i) = -\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Re(barV_i) =\n -left(Csin phi_ij - Dcos phi_ij right) \n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial Im(barV_j) = -\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial Re(barV_j) =\n -tau_ij^2B\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As before, we are neglecting the covariances between the real and imaginary parts of the measurement. If desired, we can include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfw = w_Re(barI_ji) w_Im(barI_ji)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; label = \"I₃₁, ψ₃₁\", to = 2, magnitude = 0.3, angle = 2.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" w_Re(barI_ji) = w_Im(barI_ji) = sin z_psi_ji cos z_psi_ji(v_I_ji - v_psi_ji z_I_ji^2)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEWLSStateEstimationTutorials","page":"PMU State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The solution to the PMU state estimation problem is determined by solving the linear weighted least-squares (WLS) problem, represented by the following formula:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf H^T bm Sigma^-1 mathbf H mathbf x = mathbf H^T bm Sigma^-1 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbf z in mathbb R^k denotes the vector of measurement values, mathbf H in mathbb R^k times 2n represents the coefficient matrix, and bm Sigma in mathbb R^k times k is the measurement error covariance matrix.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Implementation","page":"PMU State Estimation","title":"Implementation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid initiates the PMU state estimation framework by setting up the WLS model, as illustrated in the following:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Coefficient-Matrix","page":"PMU State Estimation","title":"Coefficient Matrix","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Using the above-described equations, JuliaGrid forms the coefficient matrix mathbfH in mathbbR^k times 2n:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐇 = analysis.method.coefficient","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this matrix, each row corresponds to a specific measurement in the rectangular coordinate system. Therefore, the i-th PMU is associated with the 2i - 1 index of the row, representing the real part of the phasor measurement, while the 2i row corresponds to the imaginary part of the phasor measurement. Columns are ordered based on how the state variables are defined mathbf x equivmathbfV_textremathbfV_textim.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Precision-Matrix","page":"PMU State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid opts not to retain the covariance matrix bm Sigma but rather stores its inverse, the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. The order of these values corresponds to the description provided for the coefficient matrix. Users can access these values using the following command:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The precision matrix does not maintain a diagonal form, indicating that correlations between the real and imaginary parts of the phasor measurements are included in the model. To ignore these correlations, simply omit the correlated keyword within the function that adds a PMU. For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\n\n@pmu(label = \"PMU ?\", noise = false)\naddPmu!(system, device; bus = 1, magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = 2, magnitude = 0.87, angle = -0.15)\naddPmu!(system, device; from = 1, magnitude = 0.30, angle = -0.71)\naddPmu!(system, device; from = 2, magnitude = 0.31, angle = -0.49)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following this, we recreate the WLS state estimation model:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon inspection, it becomes evident that the precision matrix maintains a diagonal structure:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Mean-Vector","page":"PMU State Estimation","title":"Mean Vector","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To retrieve the vector mathbf z, containing the means of Gaussian distributions for each measurement, users can utilize:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"These values represent measurement values in the rectangular coordinate system as described earlier.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Estimate-of-State-Variables","page":"PMU State Estimation","title":"Estimate of State Variables","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Next, the WLS equation is solved to obtain the estimate of state variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\thatmathbf x = mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T bm Sigma^-1 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This process is executed using the solve! function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The initial step involves the LU factorization of the gain matrix:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf G = mathbf H^T bm Sigma^-1 mathbf H = mathbf L mathbf U","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the gain matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Access to the factorized gain matrix is available through:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Finally, JuliaGrid obtains the solution in the rectangular coordinate system and then transforms these solutions into the standard form given in the polar coordinate system.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, can be retrieved using the variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nIt is essential to note that the slack bus does not exist in the case of the PMU state estimation model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEOrthogonalWLSStateEstimationTutorials","page":"PMU State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2]. This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can employ an alternative approach:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device, Orthogonal)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"\tmathbf H^T mathbf W mathbf H hatmathbf x = mathbf H^T mathbf W mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf H hatmathbf x = left(mathbf W^12 mathbf Hright)^T mathbf W^12 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH^T barmathbfH hatmathbf x = barmathbfH^T barmathbfz","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH = mathbf W^12 mathbf H barmathbfz = mathbf W^12 mathbf z","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"At this point, QR factorization is performed on the rectangular matrix:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barmathbfH = mathbf W^12 mathbf H = mathbfQmathbfR","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Executing this procedure involves the solve! function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the solution, JuliaGrid avoids materializing the orthogonal matrix mathbfQ and proceeds to solve the system, resulting in the estimate of bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, where i in mathcalN:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSEBadDataTutorials","page":"PMU State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = 3, magnitude = 2.5, angle = 0.1)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we will construct the WLS state estimation model and solve it:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals in the rectangular coordinate system based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" r_i = z_i - h_i(hat mathbf x) i in mathcalM","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf H mathbf H^T bm Sigma^-1 mathbf H^-1 mathbf H^T","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"is removed from the PMU model and marked as out-of-service. Specifically, either the real or imaginary part of the corresponding measurement is identified as the outlier. Consequently, both parts of the measurement are removed from the PMU state estimation model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we can immediately solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUSELAVTutorials","page":"PMU State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"It can be demonstrated that the problem can be expressed as a linear programming problem. This section outlines the method as described in [5, Sec. 6.5]. To revisit, we consider the system of linear equations:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbfz=mathbfh(mathbf x)+mathbfu+mathbfw","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize mathbf a^T mathbf r\n textsubjectto mathbfz - mathbfH mathbf x =mathbf r\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, mathbf a in mathbb R^k is the vector with all entries equal to one, and mathbf r represents the vector of measurement residuals. Let bm eta be defined in a manner that ensures:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf r preceq bm eta","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"and replace the above inequality with two equalities using the introduction of two non-negative slack variables mathbf q in mathbb R_ge 0^k and mathbf w in mathbb R_ge 0^k:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r - mathbf q = -bm eta \n mathbf r + mathbf w = bm eta\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us now define four additional non-negative variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf x_x in mathbb R_ge 0^n mathbf x_y in mathbb R_ge 0^n \n mathbf r_x in mathbb R_ge 0^k mathbf r_y in mathbb R_ge 0^k","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"where:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" mathbf x = mathbf x_x - mathbf x_y mathbf r = mathbf r_x - mathbf r_y\n mathbf r_x = cfrac12 mathbf q mathbf r_y = cfrac12 mathbf w","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r - 2mathbf r_x = -2bm eta \n mathbf r + 2 mathbf r_y = 2bm eta\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"that is:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n mathbf r_x + mathbf r_y = bm eta mathbf r = mathbf r_x - mathbf r_y\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize mathbf a^T (mathbf r_x + mathbf r_y)\n textsubjectto mathbfH(mathbf x_x - mathbf x_y) + mathbf r_x - mathbf r_y = mathbfz \n mathbf x_x succeq mathbf 0 mathbf x_y succeq mathbf 0 \n mathbf r_x succeq mathbf 0 mathbf r_y succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"As a result, we obtain optimal values for the four additional non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" hatmathbf x = mathbf x_x - mathbf x_y","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can retrieve the estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, using:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#optimalpmu","page":"PMU State Estimation","title":"Optimal PMU Placement","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid utilizes the optimal PMU placement algorithm proposed in [23]. The optimal positioning of PMUs is framed as an integer linear programming problem, expressed as:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n textminimize sum_i=1^n d_i\n textsubjectto mathbf A mathbf d ge mathbf a\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Here, the vector mathbf d = d_1dotsd_n^T serves as the optimization variable, where d_i in mathbbF = 01 is the PMU placement or a binary decision variable associated with the bus i in mathcalN. The all-one vector mathbf a is of dimension n. The binary connectivity matrix mathbf A in mathbbF^n times n can be directly derived from the bus nodal matrix mathbf Y by converting its entries into binary form [24].","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Consequently, we obtain the binary vector mathbf d = d_1dotsd_n^T, where d_i = 1, i in mathcalN, suggests that a PMU should be placed at bus i. The primary aim of PMU placement in the power system is to determine a minimal set of PMUs such that the entire system is observable without relying on traditional measurements [23]. Specifically, when we observe d_i = 1, it indicates that the PMU is installed at bus i in mathcalN to measure bus voltage phasor as well as all current phasors across branches incident to bus i.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Determining the optimal PMU placement involves analyzing the created power system. For example:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using GLPK\nusing JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 2, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nplacement = pmuPlacement(system, GLPK.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The placement variable contains data regarding the optimal placement of measurements. It lists all buses i in mathcalN that satisfy d_i = 1:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.bus","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This PMU installed at bus 2 will measure the bus voltage phasor at the corresponding bus and all current phasors at the branches incident to bus 2 located at the from-bus or to-bus ends. These data are stored in the variables:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.from\nplacement.to","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUPowerAnalysisTutorials","page":"PMU State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-Injections","page":"PMU State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUGeneratorPowerInjectionsManual","page":"PMU State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can calculate the active and reactive power injections supplied by generators at each bus i in mathcalN by summing the active and reactive power injections and the active and reactive power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":" beginaligned\n P_textpi = P_i + P_textdi\n Q_textpi = Q_i + Q_textdi\n endaligned","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The active and reactive power injections from the generators at each bus are stored as vectors, denoted by mathbfP_textp = P_textpi and mathbfQ_textp = Q_textpi, which can be obtained using:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₚ = analysis.power.supply.active\n𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Bus-Shunt-Elements","page":"PMU State Estimation","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-Flows","page":"PMU State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Branch-Shunt-Elements","page":"PMU State Estimation","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Power-at-Branch-Series-Elements","page":"PMU State Estimation","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#PMUCurrentAnalysisTutorials","page":"PMU State Estimation","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-Injections","page":"PMU State Estimation","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-Flows","page":"PMU State Estimation","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"tutorials/pmuStateEstimation/#Current-at-Branch-Series-Elements","page":"PMU State Estimation","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/powerFlow/#PowerFlowAPI","page":"Power Flow","title":"Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"For further information on this topic, please see the AC Power Flow or DC Power Flow sections of the Manual. Below, we have provided a list of functions that can be utilized for power flow analysis.","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"To load power flow API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"using JuliaGrid","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#AC-Power-Flow","page":"Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"newtonRaphson\nfastNewtonRaphsonBX\nfastNewtonRaphsonXB\ngaussSeidel\nmismatch!\nsolve!\nstartingVoltage!\nreactiveLimit!\nadjustAngle!","category":"page"},{"location":"api/powerFlow/#DC-Power-Flow","page":"Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"dcPowerFlow\nsolve!","category":"page"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#AC-Power-Flow-2","page":"Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"newtonRaphson\nfastNewtonRaphsonBX\nfastNewtonRaphsonXB\ngaussSeidel\nmismatch!(::PowerSystem, ::ACPowerFlow{NewtonRaphson})\nsolve!(::PowerSystem, ::ACPowerFlow{NewtonRaphson})\nstartingVoltage!\nreactiveLimit!\nadjustAngle!","category":"page"},{"location":"api/powerFlow/#JuliaGrid.newtonRaphson","page":"Power Flow","title":"JuliaGrid.newtonRaphson","text":"newtonRaphson(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the Newton-Raphson method to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrix, its factorization, mismatches, increments, and indices.\n\nExamples\n\nSet up the Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\n\nSet up the Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.fastNewtonRaphsonBX","page":"Power Flow","title":"JuliaGrid.fastNewtonRaphsonBX","text":"fastNewtonRaphsonBX(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the fast Newton-Raphson method of version BX to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrices, their factorizations, mismatches, increments, and indices.\n\nExamples\n\nSet up the fast Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonBX(system)\n\nSet up the fast Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonBX(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.fastNewtonRaphsonXB","page":"Power Flow","title":"JuliaGrid.fastNewtonRaphsonXB","text":"fastNewtonRaphsonXB(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the fast Newton-Raphson method of version XB to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations within each iteration. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The Jacobian matrices, their factorizations, mismatches, increments, and indices.\n\nExamples\n\nSet up the fast Newton-Raphson method utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonXB(system)\n\nSet up the fast Newton-Raphson method utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = fastNewtonRaphsonXB(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.gaussSeidel","page":"Power Flow","title":"JuliaGrid.gaussSeidel","text":"gaussSeidel(system::PowerSystem)\n\nThe function sets up the Gauss-Seidel method to solve the AC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework.\n\nUpdates\n\nIf the AC model has not been created, the function automatically initiates an update within the ac field of the PowerSystem type. It also performs a check on bus types and rectifies any mistakes present.\n\nReturns\n\nThe function returns an instance of the ACPowerFlow type, which includes the following fields:\n\nvoltage: The bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\ncurrent: The variable allocated to store the currents.\nmethod: The bus complex voltages and indices.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = gaussSeidel(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.mismatch!-Tuple{PowerSystem, ACPowerFlow{NewtonRaphson}}","page":"Power Flow","title":"JuliaGrid.mismatch!","text":"mismatch!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function calculates both active and reactive power injection mismatches.\n\nUpdates\n\nThis function updates the mismatch variables in the Newton-Raphson and fast Newton-Raphson methods. It should be employed during the iteration loop before invoking the solve! function.\n\nReturns\n\nThe function returns maximum absolute values of the active and reactive power injection mismatches, which can be utilized to terminate the iteration loop of the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel methods employed to solve the AC power flow problem.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nmismatch!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/powerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, ACPowerFlow{NewtonRaphson}}","page":"Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function employs the Newton-Raphson, fast Newton-Raphson, or Gauss-Seidel method to solve the AC power flow model and calculate bus voltage magnitudes and angles.\n\nAfter the mismatch! function is called, this function should be executed to perform a single iteration of the method.\n\nUpdates\n\nThe calculated voltages are stored in the voltage field of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"method"},{"location":"api/powerFlow/#JuliaGrid.startingVoltage!","page":"Power Flow","title":"JuliaGrid.startingVoltage!","text":"startingVoltage!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function extracts bus voltage magnitudes and angles from the PowerSystem composite type and assigns them to the ACPowerFlow type, enabling users to initialize voltage values as required.\n\nUpdates\n\nThis function only updates the voltage field of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nupdateBus!(system, analysis; label = 14, reactive = 0.13, magnitude = 1.2, angle = -0.17)\n\nstartingVoltage!(system, analysis)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.reactiveLimit!","page":"Power Flow","title":"JuliaGrid.reactiveLimit!","text":"reactiveLimit!(system::PowerSystem, analysis::ACPowerFlow)\n\nThe function verifies whether the generators in a power system exceed their reactive power limits. This is done by setting the reactive power of the generators to within the limits if they are violated after determining the bus voltage magnitudes and angles. If the limits are violated, the corresponding generator buses or the slack bus are converted to demand buses.\n\nUpdates\n\nThe function assigns values to the generator.output.active and bus.supply.active variables of the PowerSystem type.\n\nAdditionally, it examines the reactive powers of the generators and adjusts them to their maximum or minimum values if they exceed the specified threshold. This results in the modification of the variable generator.output.reactive of the PowerSystem type accordingly.\n\nAs a result of this adjustment, the bus.supply.reactive variable is also updated, and the bus types specified in bus.layout.type are modified. If the slack bus is converted, the bus.layout.slack field is correspondingly adjusted.\n\nReturns\n\nThe function returns the variable to indicate which buses violate the limits, with -1 indicating a violation of the minimum limits and 1 indicating a violation of the maximum limits.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nviolate = reactiveLimit!(system, analysis)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.adjustAngle!","page":"Power Flow","title":"JuliaGrid.adjustAngle!","text":"adjustAngle!(system::PowerSystem, analysis::ACPowerFlow; slack)\n\nThe function modifies the bus voltage angles based on a different slack bus than the one identified by the bus.layout.slack field.\n\nFor instance, if the reactive power of the generator exceeds the limit on the slack bus, the reactiveLimit! function will change that bus to the demand bus and designate the first generator bus in the sequence as the new slack bus. After obtaining the updated AC power flow solution based on the new slack bus, it is possible to adjust the voltage angles to align with the angle of the original slack bus.\n\nKeyword\n\nThe slack keyword specifies the bus label for which we want to adjust voltage angles.\n\nUpdates\n\nThis function only updates the voltage.angle variable of the ACPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nreactiveLimit!(system, analysis)\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\nadjustAngle!(system, analysis; slack = 1)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"","category":"page"},{"location":"api/powerFlow/#DC-Power-Flow-2","page":"Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"api/powerFlow/","page":"Power Flow","title":"Power Flow","text":"dcPowerFlow\nsolve!(::PowerSystem, ::DCPowerFlow)","category":"page"},{"location":"api/powerFlow/#JuliaGrid.dcPowerFlow","page":"Power Flow","title":"JuliaGrid.dcPowerFlow","text":"dcPowerFlow(system::PowerSystem, [factorization::Factorization = LU])\n\nThe function sets up the framework to solve the DC power flow.\n\nArguments\n\nThe function requires the PowerSystem composite type to establish the framework. Next, the Factorization argument, while optional, determines the method used to solve the linear system of equations. It can take one of the following values:\n\nLU: utilizes LU factorization (default),\nLDLt: utilizes LDLt factorization,\nQR: utilizes QR factorization.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCPowerFlow type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The factorized nodal matrix.\n\nExamples\n\nSet up the DC power flow utilizing LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\n\nSet up the DC power flow utilizing QR factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system, QR)\n\n\n\n\n\n","category":"function"},{"location":"api/powerFlow/#JuliaGrid.solve!-Tuple{PowerSystem, DCPowerFlow}","page":"Power Flow","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCPowerFlow)\n\nThe function solves the DC power flow model and calculates bus voltage angles.\n\nUpdates\n\nThe calculated voltage angles are stored in the voltage field of the DCPowerFlow type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"tutorials/acStateEstimation/#ACStateEstimationTutorials","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To initiate the process, let us construct the PowerSystem type and formulate the AC model:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, active = 0.5)\naddBus!(system; label = 2, type = 1, reactive = 0.3)\naddBus!(system; label = 3, type = 1, active = 0.5)\n\n@branch(resistance = 0.02, susceptance = 0.04)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.6)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.7)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.2)\n\naddGenerator!(system; label = 1, bus = 1, active = 3.2, reactive = 0.2)\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we will introduce the Measurement type and incorporate a set of measurement devices mathcalM into the graph mathcalG. The AC state estimation includes a set of voltmeters mathcalV, ammeters mathcalI, wattmeters mathcalP, varmeters mathcalQ, and PMUs barmathcalP, with PMUs being able to integrate into AC state estimation in either rectangular coordinates or polar coordinates. This process of adding measurement devices will be carried out in the State Estimation Model section. Currently, we are only initializing the Measurement type at this stage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device = measurement()\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or measurement i in mathcalM, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACSEModelTutorials","page":"AC State Estimation","title":"State Estimation Model","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In accordance with the AC Model, the AC state estimation treats bus voltages as state variables, which we denoted by mathbf x equiv bm Theta mathbfV^T. The state vector encompasses two components:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"bm Theta in mathbbR^n-1, representing bus voltage angles,\nmathbf V in mathbbR^n, representing bus voltage magnitudes.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, the total number of state variables is n_textu = 2n-1, accounting for the fact that the voltage angle for the slack bus is known.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Within the JuliaGrid framework for AC state estimation, the methodology encompasses bus voltage magnitudes, branch current magnitudes, active powers, reactive powers, and phasor measurements. These measurements contribute to the construction of a nonlinear system of equations:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, mathbfh(mathbf x)= h_1(mathbf x), dots, h_k(mathbf x)^T represents the vector of nonlinear measurement functions, where k is the number of measurements, mathbfz = z_1dotsz_k^T denotes the vector of measurement values, and mathbfu = u_1dotsu_k^T represents the vector of measurement errors. It is worth noting that the number of equations in the system is equal to k = mathcalV cup mathcalI cup mathcalP cup mathcalQ + 2barmathcalP.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These errors are assumed to follow a Gaussian distribution with a zero mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T. These covariances exist only if PMUs are observed in rectangular coordinates and correlation is required.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, the nonlinear system of equations is structured according to the specific devices:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginbmatrix\n mathbfz_mathcalV3pt\n mathbfz_mathcalI3pt\n mathbfz_mathcalP3pt\n mathbfz_mathcalQ3pt\n mathbfz_barmathcalP\n endbmatrix =\n beginbmatrix\n mathbfh_mathcalV(mathbf x)3pt\n mathbfh_mathcalI(mathbf x)3pt\n mathbfh_mathcalP(mathbf x)3pt\n mathbfh_mathcalQ(mathbf x)3pt\n mathbfh_barmathcalP(mathbf x)\n endbmatrix +\n beginbmatrix\n mathbfu_mathcalV3pt\n mathbfu_mathcalI3pt\n mathbfu_mathcalP3pt\n mathbfu_mathcalQ3pt\n mathbfu_barmathcalP\n endbmatrix","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Please note that each error vector, denoted as mathbfu_i, where i in mathcalV mathcalI mathcalP mathcalQ, is associated with the variance vector mathbfv_i. However, for PMUs, the error vector mathbfu_barmathcalP, along with its variance vector mathbfv_barmathcalP, can also be associated with the covariance vector mathbfw_barmathcalP.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In summary, upon user definition of the measurement devices, each i-th legacy measurement device is linked to the measurement function h_i(mathbf x), the corresponding measurement value z_i, and the measurement variance v_i. Meanwhile, each i-th PMU is associated with two measurement functions h_2i-1(mathbf x), h_2i(mathbf x), along with their respective measurement values z_2i-1, z_2i, as well as their variances v_2i-1, v_2i, and possibly covariances w_2i-1, w_2i.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Typically, the AC state estimator is obtained using the Gauss-Newton method or its variation, which involves constructing the Jacobian matrix. Therefore, in addition to the aforementioned elements, we also need Jacobian expressions corresponding to the measurement functions, which are also provided below.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Bus-Voltage-Magnitude-Measurements","page":"AC State Estimation","title":"Bus Voltage Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a voltmeter V_i in mathcalV at bus i in mathcalN, users specify the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalV = z_V_i mathbfv_mathcalV = v_V_i mathbfh_mathcalV(mathbf x) = h_V_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; label = \"V₁\", bus = 1, magnitude = 1.0, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the bus voltage magnitude measurement function is simply defined as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_V_i(mathbf x) = V_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expression:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" \tcfracmathrm partialh_V_i(mathbf x) mathrm partial V_i=1","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#FromCurrentMagnitudeMeasurements","page":"AC State Estimation","title":"From-Bus End Current Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing an ammeter at branch (ij) in mathcalE, it can be placed at the from-bus end, denoted as I_ij in mathcalI, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalI = z_I_ij mathbfv_mathcalI = v_I_ij mathbfh_mathcalI(mathbf x) = h_I_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addAmmeter!(system, device; label = \"I₁₂\", from = 1, magnitude = 0.3, variance = 1e-2)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, following the guidelines outlined in the AC Model, the function defining the current magnitude at the from-bus end is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_I_ij(mathbf x) = sqrtA_I_ijV_i^2 + B_I_ijV_j^2 - 2C_I_ij cos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" begingathered\n A_I_ij = cfrac(g_ij + g_textsi)^2+(b_ij+b_textsi)^2tau_ij^4 B_I_ij = cfracg_ij^2+b_ij^2tau_ij^2 \n C_I_ij = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij^3 D_I_ij = cfracg_ijb_textsi - b_ijg_textsitau_ij^3\n endgathered","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_I_ij(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_I_ij(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_I_ij(mathbf x)mathrm partial theta_j =\n cfrac C_I_ijsin(theta_ij - phi_ij) + D_I_ijcos(theta_ij - phi_ij)V_i V_jh_I_ij(mathbf x) \n cfracmathrm partialh_I_ij(mathbf x)mathrm partial V_i =\n cfracA_I_ijV_i - C_I_ijcos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_jh_I_ij(mathbf x) \n cfracmathrm partialh_I_ij(mathbf x)mathrm partial V_j =\n cfracB_I_ijV_j - C_I_ijcos(theta_ij - phi_ij) - D_I_ijsin(theta_ij - phi_ij)V_ih_I_ij(mathbf x) \n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ToCurrentMagnitudeMeasurements","page":"AC State Estimation","title":"To-Bus End Current Magnitude Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In addition to the scenario where we add ammeters at the from-bus end, an ammeter can also be positioned at the to-bus end, denoted as I_ji in mathcalI, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalI = z_I_ji mathbfv_mathcalI = v_I_ji mathbfh_mathcalI(mathbf x) = h_I_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addAmmeter!(system, device; label = \"I₂₁\", to = 1, magnitude = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, the measurement function is as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_I_ji(mathbf x) = sqrtA_I_jiV_i^2 + B_I_jiV_j^2 - 2C_I_ji cos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" begingathered\n A_I_ji = cfracg_ij^2+b_ij^2tau_ij^2 B_I_ji = (g_ij + g_textsi)^2+(b_ij+b_textsi)^2 \n C_I_ji = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij D_I_ji = cfracg_ijb_textsi - b_ijg_textsitau_ij\n endgathered","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_I_ji(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_I_ji(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_I_ji(mathbf x)mathrm partial theta_j =\n cfracC_I_jisin(theta_ij - phi_ij) - D_I_jicos(theta_ij- phi_ij)V_i V_jh_I_ji(mathbf x) \n cfracmathrm partialh_I_ji(mathbf x)mathrm partial V_i =\n cfracA_I_jiV_i - C_I_jicos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_jh_I_ji(mathbf x) \n cfracmathrm partialh_I_ji(mathbf x)mathrm partial V_j =\n cfracB_I_jiV_j - C_I_jicos(theta_ij - phi_ij) + D_I_jisin(theta_ij - phi_ij)V_ih_I_ji(mathbf x) \n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Active-Power-Injection-Measurements","page":"AC State Estimation","title":"Active Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When adding a wattmeter P_i in mathcalP at bus i in mathcalN, users specify that the wattmeter measures active power injection and define measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_i mathbfv_mathcalP = v_P_i mathbfh_mathcalP(mathbf x) = h_P_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₃\", bus = 3, active = -0.5, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, utilizing the AC Model, we derive the function defining the active power injection as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_i(mathbf x) = V_isumlimits_j in mathcalN_i (G_ijcostheta_ij + B_ijsintheta_ij)V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathcalN_i contains buses incident to bus i, including bus i, with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_i(mathbf x)mathrm partial theta_i =\n V_isum_j in mathcalN_i (-G_ijsintheta_ij+B_ijcostheta_ij)V_j - B_iiV_i^2\n cfracmathrm partialh_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_iV_j \n cfracmathrm partialh_P_i(mathbf x)mathrm partial V_i =\n sum_j in mathcalN_i (G_ijcostheta_ij+B_ij sintheta_ij)V_j + G_ii V_i\n cfracmathrm partialh_P_i(mathbf x)mathrm partial V_j =\n (G_ijcostheta_ij+B_ijsintheta_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#From-Bus-End-Active-Power-Flow-Measurements","page":"AC State Estimation","title":"From-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, when introducing a wattmeter at branch (ij) in mathcalE, users specify that the wattmeter measures active power flow. It can be positioned at the from-bus end, denoted as P_ij in mathcalP, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_ij mathbfv_mathcalP = v_P_ij mathbfh_mathcalP(mathbf x) = h_P_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₁₂\", from = 1, active = 0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function describing active power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_ij(mathbf x) = cfracg_ij + g_textsitau_ij^2 V_i^2 - cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)rightV_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ij(mathbf x)mathrm partial theta_i =-\n cfracmathrm partialh_P_ij(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_P_ij(mathbf x)mathrm partial V_i =\n 2cfracg_ij + g_textsitau_ij^2 V_i -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)right V_j \n cfracmathrm partialh_P_ij(mathbf x)mathrm partial V_j = -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) + b_ij sin(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#To-Bus-End-Active-Power-Flow-Measurements","page":"AC State Estimation","title":"To-Bus End Active Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, a wattmeter can be placed at the to-bus end, denoted as P_ji in mathcalP, specifying the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalP = z_P_ji mathbfv_mathcalP = v_P_ji mathbfh_mathcalP(mathbf x) = h_P_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; label = \"P₂₁\", to = 1, active = -0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Thus, the function describing active power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_P_ji(mathbf x) = (g_ij + g_textsi) V_j^2 - cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij- phi_ij)right V_i V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_P_ji(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_P_ji(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) + b_ijcos(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_P_ji(mathbf x)mathrm partial V_i = -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij - phi_ij)right V_j \n cfracmathrm partialh_P_ji(mathbf x)mathrm partial V_j = 2(g_ij + g_textsi) V_j-\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Reactive-Power-Injection-Measurements","page":"AC State Estimation","title":"Reactive Power Injection Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When adding a varmeter Q_i in mathcalQ at bus i in mathcalN, users specify that the varmeter measures reactive power injection and define the measurement value, variance, and measurement function of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_i mathbfv_mathcalQ = v_Q_i mathbfh_mathcalQ(mathbf x) = h_Q_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₃\", bus = 3, reactive = 0, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, utilizing the AC Model, we derive the function defining the reactive power injection as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_i(mathbf x) = V_isumlimits_j in mathcalN_i (G_ijsintheta_ij - B_ijcostheta_ij)V_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathcalN_i contains buses incident to bus i, including bus i, with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial theta_i =\n V_isum_j in mathcalN_i (G_ijcostheta_ij+B_ijsintheta_ij)V_j - G_iiV_i^2\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial theta_j =\n -(G_ijcostheta_ij+B_ijsintheta_ij)V_iV_j \n cfracmathrm partialh_Q_i(mathbf x)mathrm partial V_i =\n sum_j in mathcalN_i (G_ijsintheta_ij-B_ijcostheta_ij)V_j - B_iiV_i\n cfracmathrm partialh_Q_i(mathbf x)mathrm partial V_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#From-Bus-End-Reactive-Power-Flow-Measurements","page":"AC State Estimation","title":"From-Bus End Reactive Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, when introducing a varmeter at branch (ij) in mathcalE, users specify that the varmeter measures reactive power flow. It can be positioned at the from-bus end, denoted as Q_ij in mathcalQ, with its measurement value, variance, and measurement function included in vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_ij mathbfv_mathcalQ = v_Q_ij mathbfh_mathcalQ(mathbf x) = h_Q_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₁₂\", from = 1, reactive = 0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function describing reactive power flow at the from-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_ij(mathbf x) = -cfracb_ij + b_textsitau_ij^2 V_i^2 - cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial theta_j = -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial V_i = -\n 2cfracb_ij + b_textsitau_ij^2 V_i -\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_j\n cfracmathrm partialh_Q_ij(mathbf x)mathrm partial V_j = -\n cfrac1tau_ij leftg_ijsin(theta_ij - phi_ij) - b_ijcos(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#To-Bus-End-Reactive-Power-Flow-Measurements","page":"AC State Estimation","title":"To-Bus End Reactive Power Flow Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, a varmeter can be placed at the to-bus end, denoted as Q_ji in mathcalQ, with its own measurement value, variance, and measurement function included in vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_mathcalQ = z_Q_ji mathbfv_mathcalQ = v_Q_ji mathbfh_mathcalQ(mathbf x) = h_Q_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVarmeter!(system, device; label = \"Q₂₁\", to = 1, reactive = -0.2, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Thus, the function describing reactive power flow at the to-bus end is defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_Q_ji(mathbf x) = -(b_ij + b_textsi) V_j^2 + cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_iV_j","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial theta_i = -\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial theta_j =\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) - b_ijsin(theta_ij - phi_ij)right V_iV_j \n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial V_i =\n cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_j\n cfracmathrm partialh_Q_ji(mathbf x)mathrm partial V_j = -\n 2(b_ij + b_textsi) V_j +\n cfrac1tau_ij leftg_ij sin(theta_ij - phi_ij) + b_ij cos(theta_ij - phi_ij)right V_i\n\tendaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-Bus-Voltage-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When a PMU (V_i theta_i) in barmathcalP is introduced at bus i in mathcalN, it will be incorporated into the AC state estimation model using rectangular coordinates by default. It will define the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barV_i) z_Im(barV_i) mathbfv_barmathcalP = v_Re(barV_i) v_Im(barV_i) mathbfh_barmathcalP(mathbf x) = h_Re(barV_i)(mathbf x) h_Im(barV_i)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₂, θ₂\", bus = 2, magnitude = 0.9, angle = -0.1,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barV_i) = z_V_i cos z_theta_i\n z_Im(barV_i) = z_V_i sin z_theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)right^2 =\n v_V_i (cos z_theta_i)^2 + v_theta_i (z_V_i sin z_theta_i)^2\n v_Im(barV_i) =\n v_V_i left cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) right^2 +\n v_theta_i left cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)right^2 =\n v_V_i (sin z_theta_i)^2 + v_theta_i (z_V_i cos z_theta_i)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Lastly, the functions defining the bus voltage phasor measurement are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barV_i)(mathbf x) = V_icos theta_i\n h_Im(barV_i)(mathbf x) = V_isin theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barV_i)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial theta_i=-V_isin theta_i \n \tcfracmathrm partialh_Re(barV_i)(mathbf x)mathrm partial V_i=cos theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barV_i)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial theta_i=V_icos theta_i\n \tcfracmathrm partialh_Im(barV_i)(mathbf x)mathrm partial V_i=sin theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barV_i) w_Im(barV_i)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₃, θ₃\", bus = 3, magnitude = 0.9, angle = -0.2,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) =\n v_V_i cfracmathrm partial mathrm partial z_V_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_V_i (z_V_i sin z_theta_i) +\n v_theta_i cfracmathrm partial mathrm partial z_theta_i (z_V_i cos z_theta_i)\n cfracmathrm partial mathrm partial z_theta_i (z_V_i sin z_theta_i)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"which results in the solution:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barV_i) = w_Im(barV_i) = cos z_theta_i sin z_theta_i(v_V_i - v_theta_i z_V_i^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-Bus-Voltage-Phasor-Measurements","page":"AC State Estimation","title":"Polar Bus Voltage Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (V_i theta_i) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_V_i z_theta_i mathbfv_barmathcalP = v_V_i v_theta_i mathbfh_barmathcalP(mathbf x) = h_V_i(mathbf x) h_theta_i(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1.0, angle = 0,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-6, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the functions defining the bus voltage phasor measurement are straightforward:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_V_i(mathbf x) = V_i\n h_theta_i(mathbf x) = theta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"with the following Jacobian expressions:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n \tcfracmathrm partialh_V_i(mathbf x)mathrm partial V_i=1 \n cfracmathrm partialh_theta_i(mathbf x)mathrm partial theta_i=1\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-From-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a PMU at branch (ij) in mathcalE, it can be placed at the from-bus end, denoted as (I_ij psi_ij) in barmathcalP, and it will be integrated into the AC state estimation model using rectangular coordinates by default. Incorporating current phasor measurements in the polar coordinate system is highly susceptible to ill-conditioned problems, especially when dealing with small values of current magnitudes. This is the reason why we typically include PMUs in the rectangular coordinate system by default.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, here we specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barI_ij) z_Im(barI_ij) mathbfv_barmathcalP = v_Re(barI_ij) v_Im(barI_ij) mathbfh_barmathcalP(mathbf x) = h_Re(barI_ij)(mathbf x) h_Im(barI_ij)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₂₃, ψ₂₃\", from = 3, magnitude = 0.3, angle = 0.4,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barI_ij) = z_I_ij cos z_psi_ij\n z_Im(barI_ij) = z_I_ij sin z_psi_ij\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Utilizing the classical theory of propagation of uncertainty [16], the variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barI_ij) = v_I_ij (cos z_psi_ij)^2 + v_psi_ij (z_I_ij sin z_psi_ij)^2 \n v_Im(barI_ij) = v_I_ij (sin z_psi_ij)^2 + v_psi_ij (z_I_ij cos z_psi_ij)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The functions defining the current phasor measurement at the from-bus end are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barI_ij)(mathbf x) = (A_psi_ij cos theta_i - B_psi_ij sin theta_i)V_i - C_psi_ij cos (theta_j + phi_ij) - D_psi_ij sin (theta_j + phi_ij)V_j \n h_Im(barI_ij)(mathbf x) = (A_psi_ij sin theta_i + B_psi_ij cos theta_i)V_i - C_psi_ij sin (theta_j + phi_ij) + D_psi_ij cos (theta_j + phi_ij)V_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barI_ij)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial theta_i =\n -(A_psi_ij sin theta_i + B_psi_ij cos theta_i)V_i\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial theta_j =\n C_psi_ij sin(theta_j + phi_ij) + D_psi_ij cos(theta_j + phi_ij) V_j \n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial V_i =\n A_psi_ij cos theta_i - B_psi_ij sintheta_i\n cfracmathrm partialh_Re(barI_ij)(mathbf x)mathrm partial V_j =\n -C_psi_ij cos(theta_j + phi_ij) + D_psi_ij sin(theta_j + phi_ij)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barI_ij)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial theta_i =\n (A_psi_ij cos theta_i - B_psi_ij sin theta_i)V_i\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial theta_j =\n -C_psi_ij cos(theta_j + phi_ij) + D_psi_ij sin(theta_j + phi_ij) V_j \n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial V_i =\n A_psi_ij sin theta_i + B_psi_ij costheta_i\n cfracmathrm partialh_Im(barI_ij)(mathbf x)mathrm partial V_j =\n -C_psi_ij sin(theta_j + phi_ij) - D_psi_ij cos(theta_j + phi_ij)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In the previous example, the user neglects the covariances between the real and imaginary parts of the measurement. However, if desired, the user can also include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barI_ij) w_Im(barI_ij)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₁₃, ψ₁₃\", from = 2, magnitude = 0.3, angle = -0.5,\nvarianceMagnitude = 1e-4, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barI_ij) = w_Im(barI_ij) = sin z_psi_ij cos z_psi_ij(v_I_ij - v_psi_ij z_I_ij^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-From-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Polar From-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (I_ij psi_ij) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_I_ij z_psi_ij mathbfv_barmathcalP = v_I_ij v_psi_ij mathbfh_barmathcalP(mathbf x) = h_I_ij(mathbf x) h_psi_ij(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₁₂, ψ₁₂\", from = 1, magnitude = 0.3, angle = -0.7,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-4, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function associated with the branch current magnitude at the from-bus end remains identical to the one provided in From-Bus End Current Magnitude Measurements. However, the function defining the branch current angle measurement is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_psi_ij(mathbf x) = mathrmatanBigg\n cfrac(A_psi_ij sintheta_i + B_psi_ij costheta_i)V_i - C_psi_ij sin(theta_j+phi_ij) + D_psi_ijcos(theta_j+phi_ij)V_j\n (A_psi_ij costheta_i - B_psi_ij sintheta_i)V_i - C_psi_ij cos(theta_j+phi_ij) - D_psi_ij sin(theta_j+phi_ij)V_j Bigg","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" A_psi_ij = cfracg_ij + g_textsitau_ij^2 B_psi_ij = cfracb_ij+b_textsitau_ij^2 \n C_psi_ij = cfracg_ijtau_ij D_psi_ij = cfracb_ijtau_ij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions associated with the branch current magnitude function h_I_ij(mathbf x) remains identical to the one provided in From-Bus End Current Magnitude Measurements. Further, Jacobian expressions corresponding to the measurement function h_psi_ij(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial theta_i =\n cfracA_I_ij V_i^2- C_I_ij cos(theta_ij- phi_ij) - D_I_ij sin (theta_ij - phi_ij) V_iV_jh_I_ij^2(mathbf x) \n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial theta_j =\n cfracB_I_ij V_j^2 - C_I_ij cos (theta_ij - phi_ij) - D_I_ij sin(theta_ij- phi_ij)V_iV_jh_I_ij^2(mathbf x) \n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial V_i = -\n cfracC_I_ij sin (theta_ij - phi_ij) + D_I_ij cos(theta_ij- phi_ij)V_j h_I_ij^2(mathbf x)\n cfracmathrm partialh_psi_ij(mathbf x)mathrm partial V_j =\n cfracC_I_ij sin (theta_ij - phi_ij) + D_I_ij cos(theta_ij- phi_ij)V_i h_I_ij^2(mathbf x)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Rectangular-To-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Rectangular To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"When introducing a PMU at branch (ij) in mathcalE, it can be placed at the to-bus end, denoted as (I_ji psi_ji) in barmathcalP, and it will be integrated into the AC state estimation model using rectangular coordinates by default. The user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_Re(barI_ji) z_Im(barI_ji) mathbfv_barmathcalP = v_Re(barI_ji) v_Im(barI_ji) mathbfh_barmathcalP(mathbf x) = h_Re(barI_ji)(mathbf x) h_Im(barI_ji)(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₃₂, ψ₃₂\", to = 3, magnitude = 0.3, angle = -2.9,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, measurement values are obtained according to:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n z_Re(barI_ji) = z_I_ji cos z_psi_ji\n z_Im(barI_ji) = z_I_ji sin z_psi_ji\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The variances can be calculated as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n v_Re(barI_ji) = v_I_ji (cos z_psi_ji)^2 + v_psi_ji (z_I_ji sin z_psi_ji)^2 \n v_Im(barI_ji) = v_I_ji (sin z_psi_ji)^2 + v_psi_ji (z_I_ji cos z_psi_ji)^2\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The functions defining the current phasor measurement at the to-bus end are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n h_Re(barI_ji)(mathbf x) = (A_psi_ji cos theta_j - B_psi_ji sin theta_j)V_j - C_psi_ji cos (theta_i - phi_ij) - D_psi_ji sin (theta_i + phi_ij)V_i\n h_Im(barI_ji)(mathbf x) = (A_psi_ji sin theta_j + B_psi_ji cos theta_j)V_j - C_psi_ji sin (theta_i + phi_ij) + D_psi_ji cos (theta_i + phi_ij)V_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions corresponding to the measurement function h_Re(barI_ji)(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial theta_i =\n C_psi_ji sin (theta_i - phi_ij) + D_psi_ji cos (theta_i - phi_ij)V_i\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial theta_j =\n -(A_psi_ji sintheta_j + B_psi_ji cos theta_j ) V_j \n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial V_i =\n - C_psi_ji cos (theta_i - phi_ij) + D_psi_ji sin(theta_i - phi_ij)\n cfracmathrm partialh_Re(barI_ji)(mathbf x)mathrm partial V_j =\n A_psi_ji cos theta_j - B_psi_ji sin theta_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"while Jacobian expressions corresponding to the measurement function h_Im(barI_ji)(mathbf x) are:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial theta_i =\n -C_psi_ji cos (theta_i - phi_ij) + D_psi_ji sin (theta_i - phi_ij)V_i\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial theta_j =\n (A_psi_ji costheta_j - B_psi_ji sin theta_j ) V_j \n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial V_i =\n - C_psi_ji sin (theta_i - phi_ij) - D_psi_ji cos(theta_i - phi_ij)\n cfracmathrm partialh_Im(barI_ji)(mathbf x)mathrm partial V_j =\n A_psi_ji sin theta_j + B_psi_ji cos theta_j\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As before, we are neglecting the covariances between the real and imaginary parts of the measurement. If desired, we can include them in the state estimation model by specifying the covariances of the vector:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfw_barmathcalP = w_Re(barI_ji) w_Im(barI_ji)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₃₁, ψ₃₁\", to = 2, magnitude = 0.3, angle = 2.5,\nvarianceMagnitude = 1e-5, varianceAngle = 1e-5, correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the covariances are obtained as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" w_Re(barI_ji) = w_Im(barI_ji) = sin z_psi_ji cos z_psi_ji(v_I_ji - v_psi_ji z_I_ji^2)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Polar-To-Bus-End-Current-Phasor-Measurements","page":"AC State Estimation","title":"Polar To-Bus End Current Phasor Measurements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the user chooses to include phasor measurement (I_ji psi_ji) in barmathcalP in polar coordinates in the AC state estimation model, the user will specify the measurement values, variances, and measurement functions of vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz_barmathcalP = z_I_ji z_psi_ji mathbfv_barmathcalP = v_I_ji v_psi_ji mathbfh_barmathcalP(mathbf x) = h_I_ji(mathbf x) h_psi_ji(mathbf x)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"For example:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addPmu!(system, device; label = \"I₂₁, ψ₂₁\", to = 1, magnitude = 0.3, angle = 2.3,\nvarianceMagnitude = 1e-2, varianceAngle = 1e-3, polar = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, the function associated with the branch current magnitude at the to-bus end remains identical to the one provided in To-Bus End Current Magnitude Measurements. However, the function defining the branch current angle measurement is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" h_psi_ji(mathbf x) = mathrmatanBigg\n cfrac(A_psi_ji sintheta_j + B_psi_ji costheta_j)V_j - C_psi_ji sin(theta_i-phi_ij) + D_psi_jicos(theta_i-phi_ij)V_i\n (A_psi_ji costheta_j - B_psi_ji sintheta_j)V_j - C_psi_ji cos(theta_i-phi_ij) - D_psi_ji sin(theta_i-phi_ij)V_i Bigg","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" A_psi_ji = g_ij + g_textsi B_psi_ji = b_ij + b_textsi \n C_psi_ji = cfracg_ijtau_ij D_psi_ji = cfracb_ijtau_ij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Jacobian expressions associated with the branch current magnitude function h_I_ji(mathbf x) remains identical to the one provided in To-Bus End Current Magnitude Measurements. Further, Jacobian expressions corresponding to the measurement function h_psi_ji(mathbf x) are defined as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial theta_i =\n cfracA_I_ji V_i^2- C_I_ji cos(theta_ij- phi_ij) + D_I_ji sin (theta_ij - phi_ij) V_iV_jh_I_ji^2(mathbf x) \n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial theta_j =\n cfracB_I_ji V_j^2 - C_I_ji cos (theta_ij - phi_ij) + D_I_ji sin(theta_ij- phi_ij)V_iV_jh_I_ji^2(mathbf x) \n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial V_i =\n -cfracC_I_ji sin (theta_ij - phi_ij) - D_I_ji cos(theta_ij- phi_ij)V_j h_I_ji^2(mathbf x)\n cfracmathrm partialh_psi_ji(mathbf x)mathrm partial V_j =\n cfracC_I_ji sin (theta_ij - phi_ij) - D_I_ji cos(theta_ij- phi_ij)V_i h_I_ji^2(mathbf x)\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACSEWLSStateEstimationTutorials","page":"AC State Estimation","title":"Weighted Least-Squares Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Given the available set of measurements mathcalM, the weighted least-squares estimator hatmathbf x, i.e., the solution of the weighted least-squares problem, can be found using the Gauss-Newton method:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tBigmathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf J (mathbf x^(nu))Big mathbf Delta mathbf x^(nu) =\n\t\tmathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf x^(nu+1) = mathbf x^(nu) + mathbf Delta mathbf x^(nu)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where nu = 012dots is the iteration index, mathbf Delta mathbf x in mathbb R^n_textu is the vector of increments of the state variables, mathbf J (mathbf x)in mathbb R^k times n_textu is the Jacobian matrix of measurement functions mathbf h (mathbf x) at mathbf x=mathbf x^(nu), bm Sigma in mathbb R^k times k is a measurement error covariance matrix, and mathbf r (mathbf x) = mathbfz - mathbf h (mathbf x) is the vector of residuals [13, Ch. 10]. It is worth noting that assuming uncorrelated measurement errors leads to a diagonal covariance matrix bm Sigma corresponding to measurement variances. However, when incorporating PMUs in a rectangular coordinate system and aiming to observe error correlation, this matrix loses its diagonal form.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The non-linear or AC state estimation represents a non-convex problem arising from the non-linear measurement functions [17]. Due to the fact that the values of state variables usually fluctuate in narrow boundaries, the non-linear model represents the mildly non-linear problem, where solutions are in a reasonable-sized neighborhood which enables the use of the Gauss-Newton method. The Gauss-Newton method can produce different rates of convergence, which can be anywhere from linear to quadratic [18, Sec. 9.2]. The convergence rate in regard to power system state estimation depends on the topology and measurements, and if parameters are consistent (e.g., free bad data measurement set), the method shows near quadratic convergence rate [13, Sec. 11.2].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Initialization","page":"AC State Estimation","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us begin by setting up a new set of measurements for the defined power system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device = measurement()\n\n@wattmeter(label = \"Watmeter ?\")\naddWattmeter!(system, device; bus = 3, active = -0.5, variance = 1e-3)\naddWattmeter!(system, device; from = 1, active = 0.2, variance = 1e-4)\n\n@varmeter(label = \"Varmeter ?\")\naddVarmeter!(system, device; bus = 2, reactive = -0.3, variance = 1e-3)\naddVarmeter!(system, device; from = 1, reactive = 0.2, variance = 1e-4)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = 1, magnitude = 1.0, angle = 0, polar = true)\naddPmu!(system, device; bus = 3, magnitude = 0.9, angle = -0.2)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To compute the voltage magnitudes and angles of buses using the Gauss-Newton method in JuliaGrid, we need to first execute the acModel! function to set up the system. Then, initialize the Gauss-Newton method using the gaussNewton function. The following code snippet demonstrates this process:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"acModel!(system)\nanalysis = gaussNewton(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Initially, the gaussNewton function constructs the mean vector holding measurement values:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐳 = analysis.method.mean","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, it forms the precision or weighting matrix denoted as mathbf W = bm Sigma^-1. We can access these values using the following command:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, using initial bus voltage magnitudes and angles from the PowerSystem type, the function creates the starting vector mathbfx^(0) of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0) for the Gauss-Newton method:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we utilize a \"flat start\" approach in our method. It is important to keep in mind that when dealing with initial conditions in this manner, the Gauss-Newton method may encounter difficulties.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Iterative-Process","page":"AC State Estimation","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To apply the Gauss-Newton method, JuliaGrid provides the solve! function. This function is utilized iteratively until a stopping criterion is met, as demonstrated in the following code snippet:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"for iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function solve! calculates the vector of residuals at each iteration using the equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf r (mathbf x^(nu)) = mathbfz - mathbf h (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resulting vector from these calculations is stored in the residual variable of the ACStateEstimation type and can be accessed through the following line of code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐫 = analysis.method.residual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The order of the residual vector follows a specific pattern. If all device types exist, the first mathcalV elements correspond to voltmeters, followed by mathcalI elements corresponding to ammeters. Then we have mathcalP elements for wattmeters and mathcalQ elements for varmeters. Finally, we have 2barmathcalP elements for PMUs. The order of these elements within specific devices follows the same order as they appear in the input data defined by the Measurement type.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"At the same time, the function forms the Jacobian matrix mathbfJ (mathbfx^(nu)) and calculates the gain matrix mathbfG (mathbfx^(nu)) using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf G (mathbf x^(nu)) = mathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf J (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The Jacobian matrix and factorized gain matrix are stored in the ACStateEstimation type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐉 = analysis.method.jacobian\n𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then finally, the function computes the vector of state variable increments using the equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t\tmathbf Delta mathbf x^(nu) = mathbf G (mathbf x^(nu))^-1 mathbf J (mathbf x^(nu))^T bm Sigma^-1 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing the gain matrix mathbfG = mathbfLmathbfU, aiming to compute the increments. Nevertheless, users have the flexibility to opt for QR or LDLt factorization as an alternative method.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Increment values are stored in the ACStateEstimation type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝚫𝐱 = analysis.method.increment","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here again, the JuliaGrid implementation of the AC state estimation follows a specific order to store the increment vector and Jacobian matrix. The vector of increments first contains n increments of bus voltage angles mathbf Delta bmTheta, followed by n increments of bus voltage magnitudes mathbf Delta mathbfV. This order also corresponds to the columns of the Jacobian matrix, while the order of rows of the Jacobian is defined according to the order of the residual vector.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Note that the increment vector and Jacobian matrix hold the slack bus with a known voltage angle. An element of the increment vector and a column of the Jacobian matrix are not deleted, and the presence on the slack bus is handled internally by JuliaGrid, which is evident from the factorization of the gain matrix.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function solve! adds the computed increment term to the previous solution to obtain a new solution:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf x^(nu + 1) = mathbf x^(nu) + mathbf Delta mathbf x^(nu)","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, the bus voltage magnitudes mathbfV = V_i and angles bmTheta = theta_i are stored in the following vectors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, the solve! function provides the maximum absolute value of state variable increments, typically employed as the termination criterion for the iteration loop. Specifically, if it falls below a predefined stopping criterion epsilon, the algorithm converges:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" max Delta x_i forall i epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Jacobian-Matrix","page":"AC State Estimation","title":"Jacobian Matrix","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a reminder, the Jacobian matrix consists of n columns representing bus voltage angles bmTheta, followed by n columns representing bus voltage magnitudes mathbfV. The arrangement of rows is structured such that the first mathcalV rows correspond to voltmeters, followed by mathcalI rows corresponding to ammeters. Then, we have mathcalP rows for wattmeters and mathcalQ rows for varmeters. Finally, there are 2barmathcalP rows for PMUs. The elements are computed based on the provided Jacobian expressions.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Precision-Matrix","page":"AC State Estimation","title":"Precision Matrix","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us revisit the precision matrix mathbf W. In the previous example, we introduced a PMU in rectangular coordinates without considering correlations between measurement errors. Now, let us update that PMU to include correlation between measurement errors:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device, analysis; label = \"PMU 2\", correlated = true)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we can examine the updated precision matrix mathbf W:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐖 = analysis.method.precision","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Observing the precision matrix, we notice that it loses its diagonal form due to the inclusion of measurement covariances in the model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Alternative-Formulation","page":"AC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from converging to a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"updatePmu!(system, device; label = \"PMU 2\", correlated = false)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To address ill-conditioned situations arising from significant differences in measurement variances, users can now employ the orthogonal factorization approach:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device, Orthogonal)\n\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To explain the method, we begin with the WLS equation:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"\t Bigmathbf J (mathbf x^(nu))^T mathbf W mathbf J (mathbf x^(nu))Big mathbf Delta mathbf x^(nu) =\n\t\tmathbf J (mathbf x^(nu))^T mathbf W mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where mathbf W = bm Sigma^-1. Subsequently, we can write:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" leftmathbf W^12 mathbf J (mathbf x^(nu))right^T mathbf W^12 mathbf J (mathbf x^(nu)) Delta mathbf x^(nu) =\n leftmathbf W^12 mathbf J (mathbf x^(nu))right^T mathbf W^12 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Consequently, we have:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu))^T barmathbf J(mathbf x^(nu)) Delta mathbf x^(nu) = barmathbf J(mathbf x^(nu))^T barmathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu)) = mathbf W^12 mathbf J (mathbf x^(nu)) barmathbf r (mathbf x^(nu)) = mathbf W^12 mathbf r (mathbf x^(nu))","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Therefore, within each iteration of the Gauss-Newton method, JuliaGrid conducts QR factorization on the rectangular matrix:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barmathbf J(mathbf x^(nu)) = mathbf W^12 mathbf J (mathbf x^(nu)) = mathbfQmathbfR","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Access to the factorized matrix is possible through:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐐 = analysis.method.factorization.Q\n𝐑 = analysis.method.factorization.R","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the solution, JuliaGrid avoids explicitly forming the orthogonal matrix mathbfQ. Once the algorithm converges, estimates of bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, where i in mathcalN can be accessed using variables:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACBadDataTutorials","page":"AC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Besides the state estimation algorithm, one of the essential state estimation routines is the bad data processing, whose main task is to detect and identify measurement errors, and eliminate them if possible. This is usually done by processing the measurement residuals [5, Ch. 5], and typically, the largest normalized residual test is used to identify bad data. The largest normalized residual test is performed after we obtained the solution of the state estimation in the repetitive process of identifying and eliminating bad data measurements one after another [19].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To illustrate this process, let us introduce a new measurement that contains an obvious outlier:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addWattmeter!(system, device; bus = 3, active = 5.1, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we will construct the AC state estimation model and solve it:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Now, the bad data processing can be executed:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In this step, we employ the largest normalized residual test, guided by the analysis outlined in [5, Sec. 5.7]. To be more precise, we compute all measurement residuals based on the obtained estimate of state variables:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" r_i = z_i - h_i(hat mathbf x) i in mathcalM","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The normalized residuals for all measurements are computed as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_i = cfracr_isqrtC_ii = cfracr_isqrtS_iiSigma_ii i in mathcalM","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In this equation, we denote the diagonal entries of the residual covariance matrix mathbf C in mathbbR^k times k as C_ii = S_iiSigma_ii, where S_ii is the diagonal entry of the residual sensitivity matrix mathbf S representing the sensitivity of the measurement residuals to the measurement errors. For this specific configuration, the relationship is expressed as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf C = mathbf S bm Sigma = bm Sigma - mathbf J (hat mathbf x) mathbf J (hat mathbf x)^T bm Sigma^-1 mathbf J (hat mathbf x)^-1 mathbf J (hat mathbf x)^T","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is important to note that only the diagonal entries of mathbf C are required. To obtain the inverse, the JuliaGrid package utilizes a computationally efficient sparse inverse method, retrieving only the necessary elements of the inverse.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The subsequent step involves selecting the largest normalized residual, and the j-th measurement is then suspected as bad data and potentially removed from the measurement set mathcalM:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_j = textmax barr_i i in mathcalM ","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can access this information using the variable:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the largest normalized residual, denoted as barr_j, satisfies the inequality:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" barr_j ge epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"the corresponding measurement is identified as bad data and subsequently removed. In this example, the bad data identification threshold is set to epsilon = 4. Users can verify the satisfaction of this inequality by inspecting:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This indicates that the measurement labeled as:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.label","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"is removed from the measurement set and marked as out-of-service.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, we can solve the system again, but this time without the removed measurement:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Following that, we check for outliers once more:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To examine the value:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.maxNormalizedResidual","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As this value is now less than the threshold epsilon = 4, the measurement is not removed, or there are no outliers. This can also be verified by observing the bad data flag:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"outlier.detect","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACLAVTutorials","page":"AC State Estimation","title":"Least Absolute Value Estimation","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The least absolute value (LAV) method provides an alternative estimation approach that is considered more robust in comparison to the WLS method. The WLS state estimation problem relies on specific assumptions about measurement errors, whereas robust estimators aim to remain unbiased even in the presence of various types of measurement errors and outliers. This characteristic eliminates the need for bad data processing, as discussed in [5, Ch. 6]. It is important to note that robustness often comes at the cost of increased computational complexity.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This section outlines the method as described in [5, Sec. 6.5]. Hence, we consider the system of nonlinear equations:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbfz=mathbfh(mathbf x)+mathbfu","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the LAV state estimator is derived as the solution to the optimization problem:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n textminimize sum_i in mathcalM r_i\n textsubjectto z_i - h_i(mathbf x) = r_i forall i in mathcalM\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"where r_i represents the i-th measurement residual. Let eta_i be defined in a manner that ensures:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" r_i leq eta_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"and replace the above inequality with two equalities using two non-negative slack variables q_i and w_i:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i - q_i = -eta_i \n r_i + w_i = eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us now define two additional non-negative variables overliner_i and underliner_i, which satisfy the following relationships:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i = overliner_i - underliner_i\n overliner_i = cfrac12 q_i \n underliner_i = cfrac12 w_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then, the above two equalities become:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n r_i - 2overliner_i = -2 eta_i \n r_i + 2 underliner_i = 2 eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"that is:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n overliner_i + underliner_i = eta_i\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, we define a vector of state variables according to two additional nonnegative vectors overlinemathbf x in mathbb R_ge 0^n_textu and underlinemathbf x in mathbb R_ge 0^n_textu, which satisfy the following relationships:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf x = overlinemathbf x - underlinemathbf x","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Hence, the optimization problem can be written:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n textminimize sum_i in mathcalM (overliner_i + underliner_i) \n textsubjectto h_i(overlinemathbf x - underlinemathbf x) + overliner_i - underliner_i = z_i forall i in mathcalM \n overliner_i geq 0 underliner_i geq 0 forall i in mathcalM \n overlinemathbf x succeq mathbf 0 underlinemathbf x succeq mathbf 0\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To form the above optimization problem, the user can call the following function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Then the user can solve the optimization problem by:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, we obtain optimal values for the four non-negative variables, while the state estimator is obtained by:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" hatmathbf x = overlinemathbf x - underlinemathbf x","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can retrieve the estimated bus voltage magnitudes hatmathbf V = hatV_i and angles hatbm Theta = hattheta_i, i in mathcalN, using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACObservabilityAnalysisTutorials","page":"AC State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The state estimation algorithm aims to estimate the values of the state variables based on the measurement model described as a system of equations. Prior to applying the state estimation algorithm, the observability analysis determines the existence and uniqueness of the solution for the underlying system of equations. In cases where a unique solution is not guaranteed, the observability analysis identifies observable islands and prescribes an additional set of equations (pseudo-measurements) to achieve a unique solution [20].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Identification-of-Observable-Islands","page":"AC State Estimation","title":"Identification of Observable Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid employs standard observability analysis performed on the linear decoupled measurement model [13, Ch. 7]. Active power measurements from wattmeters are utilized to estimate bus voltage angles, while reactive power measurements from varmeters are used to estimate bus voltage magnitudes. This necessitates that measurements of active and reactive power come in pairs.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Let us illustrate this concept with the following example, where measurements form an unobservable system:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.5, reactive = 0.01)\naddBus!(system; label = \"Bus 4\", type = 1, active = 0.2, reactive = 0.02)\naddBus!(system; label = \"Bus 5\", type = 1, active = 0.3, reactive = 0.03)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.002)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 4\", reactance = 0.02)\naddBranch!(system; label = \"Branch 4\", from = \"Bus 3\", to = \"Bus 4\", reactance = 0.03)\naddBranch!(system; label = \"Branch 5\", from = \"Bus 4\", to = \"Bus 5\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 4.2, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 3\", active = 0.2, reactive = 0.1)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 0.93)\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = -0.41)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", bus = \"Bus 2\", active = -0.1)\naddVarmeter!(system, device; label = \"Varmeter 2\", bus = \"Bus 2\", reactive = -0.01)\n\naddWattmeter!(system, device; label = \"Wattmeter 3\", bus = \"Bus 3\", active = -0.30)\naddVarmeter!(system, device; label = \"Varmeter 3\", bus = \"Bus 3\", reactive = 0.52)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"If the system lacks observability, the observability analysis needs to identify all potential observable islands that can be independently solved. An observable island is defined as follows: It is a segment of the power system where the flows across all branches within that island can be calculated solely from the available measurements. This independence holds regardless of the values chosen for the bus voltage angle at the slack bus [13, Sec. 7.1.1]. Within this context, two types of observable islands are evident:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"flow observale islands,\nmaximal observable islands.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The selection between them relies on the power system's structure and the available measurements. Opting for detecting only flow observable islands simplifies the island detection function's complexity but increases the complexity in the restoration function compared to identifying maximal observable islands.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Flow-Observale-Islands","page":"AC State Estimation","title":"Flow Observale Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To identify flow observable islands, JuliaGrid employs a topological method outlined in [21]. The process begins with the examination of all active power flow measurements from wattmeters, aiming to determine the largest sets of connected buses within the network linked by branches with active power flow measurements. Subsequently, the analysis considers individual boundary or tie active power injection measurements, involving two islands that may potentially be merged into a single observable island. The user can initiate this process by calling the function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopologicalFlow(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"As a result, four flow observable islands are identified. The first island comprises Bus 1 and Bus 2, while the second, third, and fourth islands consist of Bus 3, Bus 4, and Bus 5, respectively:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, users can inspect the tie buses and branches resulting from the observability analysis we conducted:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.tie.bus\nislands.tie.branch","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"This tie data will be utilized throughout the restoration step, where we introduce pseudo-measurements to merge the observable flow islands obtained.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Maximal-Observale-Islands","page":"AC State Estimation","title":"Maximal Observale Islands","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To identify maximal observable islands, we extend the analysis with an additional processing step. After processing individual injection tie measurements, we are left with a series of injection measurements that are not entirely contained within any observable zone. In this set of remaining tie injections, we now examine pairs involving three and only three previously determined observable zones (including individual buses). If we find such a pair, the three islands may be merged, and all injection measurements involving only nodes of this new island are excluded from further consideration. The procedure then restarts at the stage where we process tie active power injection measurements involving two and only two islands. If no mergers are possible with pairs, we then consider sets of three injection measurements involving four islands, and so on [21]. The user can initiate this by calling the function:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome reveals the identification of two maximal observable islands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"It is evident that upon comparing this result with the flow islands, the merging of the two injection measurements at Bus 2 and Bus 3 consolidated the first, second, and third flow observable islands into a single island.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here we can observe tie data:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands.tie.bus\nislands.tie.branch","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Compared to the tie data obtained after detecting flow observable islands, we now have a smaller set, indicating that the restoration step will be more computationally efficient.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Observability-Restoration","page":"AC State Estimation","title":"Observability Restoration","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Before commencing the restoration of observability in the context of the linear decoupled measurement model and observability analysis, it is imperative to ensure that the system possesses one bus voltage magnitude measurement. This necessity arises from the fact that observable islands are identified based on wattmeters, where wattmeters are tasked with estimating voltage angles. Since one voltage angle is already known from the slack bus, the same principle should be applied to bus voltage magnitudes. Therefore, to address this requirement, we add:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"addVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"After determining the islands, the observability analysis merges these islands in a manner that protect previously determined observable states from being altered by the new set of equations defined by the additional measurements, called pseudo-measurements. In general, this can be achieved by ensuring that the set of new measurements forms a non-redundant set [13, Sec. 7.3.2], i.e., the set of equations must be linearly independent with respect to the global system. The goal of observability restoration is to find this non-redundant set.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The outcome of the island detection step results in the power system being divided into m islands. Subsequently, we focus on the set of measurements mathcalM_textr subset mathcalM, which exclusively consists of:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active power injection measurements at tie buses,\nbus voltage phasor measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These measurements are retained from the phase where we identify observable islands, and are crucial in determining whether we need additional pseudo-measurements to be included in the measurement set mathcalM. In this specific example, we do not have active power injection measurements at tie buses remaining after the identification of maximal observable islands. However, if we proceed with flow observable islands to the restoration step, we will have two injection measurements at Bus 2 and Bus 3.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"However, let us introduce the matrix mathbf M_textr in mathbbR^r times m, where r = mathcalM_textr. This matrix can be conceptualized as the coefficient matrix of a reduced network, with m columns corresponding to islands and r rows associated with the set mathcalM_textr. More precisely, if we construct the coefficient matrix mathbf H_textr linked to the set mathcalM_textr in the DC framework, the matrix mathbf M_textr can be constructed by summing the columns of mathbf H_textr that belong to a specific island [22].","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Subsequently, the user needs to establish a set of pseudo-measurements, where measurements must come in pairs as well. Let us create that set:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"pseudo = measurement()\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 1\", bus = \"Bus 1\", active = 0.93)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 1\", bus = \"Bus 1\", reactive = -0.41)\n\naddWattmeter!(system, pseudo; label = \"Pseudo-Wattmeter 2\", from = \"Branch 5\", active = 0.30)\naddVarmeter!(system, pseudo; label = \"Pseudo-Varmeter 2\", from = \"Branch 5\", reactive = 0.03)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"From this set, the restoration step will only utilize the following:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"active power flow measurements between tie buses,\nactive power injection measurements at tie buses,\nbus voltage phasor measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"These pseudo-measurements mathcalM_textp will define the reduced coefficient matrix mathbf M_textp in mathbbR^p times m, where p = mathcalM_textp. In the current example, only Pseudo-Wattmeter 2 will contribute to the construction of the matrix mathbf M_textp. Similar to the previous case, measurement functions linked to the set mathcalM_textp define the coefficient matrix mathbf H_textp, and the matrix mathbf M_textp can be viewed as the sum of the columns of mathbf H_textp belonging to a specific flow island.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Additionally, users have the option to include bus voltage angle measurements from PMUs. In this scenario, restoration can be conducted without merging observable islands into one island, as each island becomes globally observable when one angle is known. It is important to note that during the restoration step, JuliaGrid initially processes active power measurements and subsequently handles bus voltage angle measurements if they are present in the set of pseudo-measurements.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Users can execute the observability restoration procedure with the following:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"restorationGram!(system, device, pseudo, islands; threshold = 1e-6)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function constructs the reduced coefficient matrix as follows:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf M = beginbmatrix mathbf M_textr mathbf M_textp endbmatrix","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"and forms the corresponding Gram matrix:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" mathbf D = mathbf M mathbf M^T","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The decomposition of mathbf D into its mathbf Q and mathbf R factors is achieved through QR factorization. Non-redundant measurements are identified by non-zero diagonal elements in mathbf R. Specifically, if the diagonal element satisfies:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" R_ii epsilon","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid designates the corresponding measurement as redundant, where epsilon represents a pre-determined zero pivot threshold, set to 1e-6 in this example. The minimal set of pseudo-measurements for observability restoration corresponds to the non-zero diagonal elements at positions associated with the candidate pseudo-measurements. It is essential to note that an inappropriate choice of the zero pivot threshold may adversely affect observability restoration. Additionally, there is a possibility that the set of pseudo-measurements mathcalM_textp may not be sufficient for achieving observability restoration.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Finally, the Pseudo-Wattmeter 2, and consequently Pseudo-Varmeter 2 measurements successfully restore observability, and these measurements are added to the device variable, which stores actual measurements:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"device.wattmeter.label\ndevice.varmeter.label","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Here, we can confirm that the new measurement set establishes the observable system formed by a single island:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"islands = islandTopological(system, device);\n\nislands.island","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Next, we can construct the AC state estimation model and resolve it to obtain estimates of bus voltages:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"analysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACPowerAnalysisTutorials","page":"AC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-Injections","page":"AC State Estimation","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#ACGeneratorPowerInjectionsManual","page":"AC State Estimation","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"We can calculate the active and reactive power injections supplied by generators at each bus i in mathcalN by summing the active and reactive power injections and the active and reactive power demanded by consumers at each bus:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":" beginaligned\n P_textpi = P_i + P_textdi\n Q_textpi = Q_i + Q_textdi\n endaligned","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The active and reactive power injections from the generators at each bus are stored as vectors, denoted by mathbfP_textp = P_textpi and mathbfQ_textp = Q_textpi, which can be obtained using:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₚ = analysis.power.supply.active\n𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Bus-Shunt-Elements","page":"AC State Estimation","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-Flows","page":"AC State Estimation","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Branch-Shunt-Elements","page":"AC State Estimation","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Power-at-Branch-Series-Elements","page":"AC State Estimation","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#PMUCurrentAnalysisTutorials","page":"AC State Estimation","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-Injections","page":"AC State Estimation","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-Flows","page":"AC State Estimation","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"","category":"page"},{"location":"tutorials/acStateEstimation/#Current-at-Branch-Series-Elements","page":"AC State Estimation","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acStateEstimation/","page":"AC State Estimation","title":"AC State Estimation","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/powerSystemModel/#powerSystemModelAPI","page":"Power System Model","title":"Power System Model","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"For further information on this topic, please see the Power System Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate power system structures, as well as to build AC and DC models of power systems.","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"using JuliaGrid","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Power-System","page":"Power System Model","title":"Power System","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem\nsavePowerSystem\nacModel!\ndcModel!","category":"page"},{"location":"api/powerSystemModel/#Bus","page":"Power System Model","title":"Bus","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!\nupdateBus!\n@bus","category":"page"},{"location":"api/powerSystemModel/#Branch","page":"Power System Model","title":"Branch","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBranch!\nupdateBranch!\n@branch","category":"page"},{"location":"api/powerSystemModel/#Generator","page":"Power System Model","title":"Generator","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addGenerator!\nupdateGenerator!\ncost!\n@generator","category":"page"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Power-System-2","page":"Power System Model","title":"Power System","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"powerSystem\nsavePowerSystem\nacModel!\ndcModel!","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.powerSystem","page":"Power System Model","title":"JuliaGrid.powerSystem","text":"powerSystem(file::String)\n\nThe function builds the composite type PowerSystem and populates bus, branch, generator and base fields. Once the composite type PowerSystem has been created, it is possible to add new buses, branches, or generators, or modify the parameters of existing ones.\n\nArgument\n\nIt requires a string path to:\n\nthe HDF5 file with the .h5 extension,\nthe Matpower file with the .m extension.\n\nReturns\n\nThe PowerSystem composite type with the following fields:\n\nbus: Data related to buses.\nbranch: Data related to branches.\ngenerator: Data related to generators.\nbase: Base power and base voltages.\nmodel: Data associated with AC and DC analyses.\n\nUnits\n\nJuliaGrid stores all data in per-units and radians format which are fixed, the exceptions are base values in volt-amperes and volts. The prefixes for these base values can be changed using the @base macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\n\n\n\n\npowerSystem()\n\nAlternatively, the PowerSystem composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed. This generates an empty PowerSystem type, with only the base power initialized to 1.0e8 volt-amperes (VA).\n\nExample\n\nsystem = powerSystem()\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.savePowerSystem","page":"Power System Model","title":"JuliaGrid.savePowerSystem","text":"savePowerSystem(system::PowerSystem; path::String, reference::String, note::String)\n\nThe function saves the power system's data in the HDF5 file using the fields bus, branch, generator, and base from the PowerSystem composite type.\n\nKeywords\n\nThe location and file name of the HDF5 file is specified by the mandatory keyword path in the format of \"path/name.h5\". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.\n\nView HDF5 File\n\nTo view the saved HDF5 file, you can use the HDFView software.\n\nExample\n\nsystem = powerSystem(\"case14.m\")\nsavePowerSystem(system; path = \"D:/case14.h5\")\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.acModel!","page":"Power System Model","title":"JuliaGrid.acModel!","text":"acModel!(system::PowerSystem)\n\nThe function generates vectors and matrices based on the power system topology and parameters associated with AC analyses.\n\nUpdates\n\nThe function updates the model.ac field within the PowerSystem composite type, populating the following variables:\n\nnodalMatrix: The nodal matrix.\nnodalMatrixTranspose: The transpose of the nodal matrix.\nnodalFromFrom: The Y-parameters of the two-port branches.\nnodalFromTo: The Y-parameters of the two-port branches.\nnodalToTo: The Y-parameters of the two-port branches.\nnodalToFrom: The Y-parameters of the two-port branches.\nadmittance: The branch admittances.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\nacModel!(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.dcModel!","page":"Power System Model","title":"JuliaGrid.dcModel!","text":"dcModel!(system::PowerSystem)\n\nThe function generates vectors and matrices based on the power system topology and parameters associated with DC analyses.\n\nUpdates\n\nThe function updates the model.dc field within the PowerSystem composite type, populating the following variables:\n\nnodalMatrix: The nodal matrix.\nadmittance: The branch admittances.\nshiftPower: The active powers related to phase-shifting transformers.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndcModel!(system)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Bus-2","page":"Power System Model","title":"Bus","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBus!\nupdateBus!\n@bus","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addBus!","page":"Power System Model","title":"JuliaGrid.addBus!","text":"addBus!(system::PowerSystem; label, type, active, reactive, conductance, susceptance,\n magnitude, angle, minMagnitude, maxMagnitude, base, area, lossZone)\n\nThe function adds a new bus to the PowerSystem composite type.\n\nKeywords\n\nThe bus is defined with the following keywords:\n\nlabel: Unique label for the bus.\ntype: Bus type:\ntype = 1: demand bus (PQ),\ntype = 2: generator bus (PV),\ntype = 3: slack bus (Vθ).\nactive (pu or W): Active power demand at the bus.\nreactive (pu or VAr): Reactive power demand at the bus.\nconductance (pu or W): Active power demanded of the shunt element.\nsusceptance (pu or VAr): Reactive power injected/demanded of the shunt element.\nmagnitude (pu or V): Initial value of the bus voltage magnitude.\nangle (rad or deg): Initial value of the bus voltage angle.\nminMagnitude (pu or V): Minimum bus voltage magnitude value.\nmaxMagnitude (pu or V): Maximum bus voltage magnitude value.\nbase (V): Voltage base value.\narea: Area number.\nlossZone: Loss zone.\n\nUpdates\n\nThe function updates the bus field of the PowerSystem composite type.\n\nDefault Settings\n\nThe default settings for certain keywords are as follows: type = 1, magnitude = 1.0, minMagnitude = 0.9, maxMagnitude = 1.1, and base = 138e3. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @bus macro.\n\nUnits\n\nBy default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.\n\nExamples\n\nAdding a bus using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 0.25, angle = 0.175, base = 132e3)\n\nAdding a bus using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 25.0, angle = 10.026, base = 132.0)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateBus!","page":"Power System Model","title":"JuliaGrid.updateBus!","text":"updateBus!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing bus.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific bus, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBus! function, along with their respective values. Ensure that the label keyword matches the label of the existing bus you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the bus field within the PowerSystem composite type, and in cases where parameters impact variables in the ac field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBus! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\nupdateBus!(system; label = \"Bus 1\", active = 0.15, susceptance = 0.15)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@bus","page":"Power System Model","title":"JuliaGrid.@bus","text":"@bus(kwargs...)\n\nThe macro generates a template for a bus, which can be utilized to define a bus using the addBus! function.\n\nKeywords\n\nTo define the bus template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBus! function, along with their corresponding values.\n\nUnits\n\nBy default, the keyword parameters use per-units (pu) and radians (rad) as units, with the exception of the base keyword argument, which is in volts (V). However, users have the option to use other units instead of per-units and radians, or to specify prefixes for base voltage by using the @power and @voltage macros.\n\nExamples\n\nAdding a bus template using the default unit system:\n\nsystem = powerSystem()\n\n@bus(type = 2, active = 0.25, angle = 0.1745)\naddBus!(system; label = \"Bus 1\", reactive = -0.04, base = 132e3)\n\nAdding a bus template using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\n@bus(type = 2, active = 25.0, angle = 10.0, base = 132.0)\naddBus!(system; label = \"Bus 1\", reactive = -4.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Branch-2","page":"Power System Model","title":"Branch","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addBranch!\nupdateBranch!\n@branch","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addBranch!","page":"Power System Model","title":"JuliaGrid.addBranch!","text":"addBranch!(system::PowerSystem, [analysis::Analysis]; label, from, to, status,\n resistance, reactance, conductance, susceptance, turnsRatio, shiftAngle,\n minDiffAngle, maxDiffAngle, minFromBus, maxFromBus, minToBus, maxToBus, type)\n\nThe function adds a new branch to the PowerSystem composite type. A branch can be added between already defined buses.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.\n\nKeywords\n\nThe branch is defined with the following keywords:\n\nlabel: Unique label for the branch.\nfrom: From-bus label, corresponds to the bus label.\nto: To-bus label, corresponds to the bus label.\nstatus: Operating status of the branch:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\nresistance (pu or Ω): Series resistance.\nreactance (pu or Ω): Series reactance.\nconductance (pu or S): Total shunt conductance.\nsusceptance (pu or S): Total shunt susceptance.\nturnsRatio: Transformer off-nominal turns ratio, equal to one for a line.\nshiftAngle (rad or deg): Transformer phase shift angle, where positive value defines delay.\nminDiffAngle (rad or deg): Minimum voltage angle difference value between from-bus and to-bus ends.\nmaxDiffAngle (rad or deg): Maximum voltage angle difference value between from-bus and to-bus ends.\nminFromBus (pu, VA, W, or A): Minimum branch flow rating at the from-bus end.\nmaxFromBus (pu, VA, W, or A): Maximum branch flow rating at the from-bus end.\nminToBus (pu, VA, W, or A): Minimum branch flow rating at the to-bus end.\nmaxToBus (pu, VA, W, or A): Maximum branch flow rating at the to-bus end.\ntype: Types of minFromBus, maxFromBus, minToBus, and maxToBus branch flow ratings:\ntype = 1: apparent power flow (pu or VA),\ntype = 2: active power flow (pu or W),\ntype = 3: current magnitude flow (pu or A).\n\nUpdates\n\nThe function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nDefault Settings\n\nBy default, certain keywords are assigned default values: status = 1, turnsRatio = 1.0, type = 1, minDiffAngle = -2pi, and maxDiffAngle = 2pi. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @branch macro.\n\nUnits\n\nThe default units for the keyword parameters are per-units (pu) and radians (rad). However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, @current, and @parameter.\n\nExamples\n\nAdding a branch using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 0.1745)\n\nAdding a branch using a custom unit system:\n\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12, shiftAngle = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateBranch!","page":"Power System Model","title":"JuliaGrid.updateBranch!","text":"updateBranch!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing branch.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter\n\nKeywords\n\nTo update a specific branch, provide the necessary kwargs input arguments in accordance with the keywords specified in the addBranch! function, along with their respective values. Ensure that the label keyword matches the label of the existing branch you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the branch field within the PowerSystem composite type, and in cases where parameters impact variables in the ac and dc fields, it automatically adjusts the fields. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBranch! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\nupdateBranch!(system; label = \"Branch 1\", reactance = 0.02, susceptance = 0.062)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@branch","page":"Power System Model","title":"JuliaGrid.@branch","text":"@branch(kwargs...)\n\nThe macro generates a template for a branch, which can be utilized to define a branch using the addBranch! function.\n\nKeywords\n\nTo define the branch template, the kwargs input arguments must be provided in accordance with the keywords specified within the addBranch! function, along with their corresponding values.\n\nUnits\n\nThe default units for the keyword parameters are per-units and radians. However, the user can choose to use other units besides per-units and radians by utilizing macros such as @power, @voltage, and @parameter.\n\nExamples\n\nAdding a branch template using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\n@branch(reactance = 0.12, shiftAngle = 0.1745)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\")\n\nAdding a branch template using a custom unit system:\n\n@voltage(pu, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.25, reactive = -0.04)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.15, reactive = 0.08)\n\n@branch(shiftAngle = 10)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n\n\n\n\n","category":"macro"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"","category":"page"},{"location":"api/powerSystemModel/#Generator-2","page":"Power System Model","title":"Generator","text":"","category":"section"},{"location":"api/powerSystemModel/","page":"Power System Model","title":"Power System Model","text":"addGenerator!\nupdateGenerator!\ncost!\n@generator","category":"page"},{"location":"api/powerSystemModel/#JuliaGrid.addGenerator!","page":"Power System Model","title":"JuliaGrid.addGenerator!","text":"addGenerator!(system::PowerSystem, [analysis::Analysis]; label, bus, status,\n active, reactive, magnitude, minActive, maxActive, minReactive, maxReactive,\n lowActive, minLowReactive, maxLowReactive, upActive, minUpReactive, maxUpReactive,\n loadFollowing, reactiveRamp, reserve10min, reserve30min, area)\n\nThe function adds a new generator to the PowerSystem composite type. The generator can be added to an already defined bus.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new generator.\n\nKeywords\n\nThe generator is defined with the following keywords:\n\nlabel: Unique label for the generator.\nbus: Label of the bus to which the generator is connected.\nstatus: Operating status of the generator:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\nactive (pu or W): Output active power.\nreactive (pu or VAr): Output reactive power.\nmagnitude (pu or V): Voltage magnitude setpoint.\nminActive (pu or W): Minimum allowed output active power value.\nmaxActive (pu or W): Maximum allowed output active power value.\nminReactive (pu or VAr): Minimum allowed output reactive power value.\nmaxReactive (pu or VAr): Maximum allowed output reactive power value.\nlowActive (pu or W): Lower allowed active power output value of PQ capability curve.\nminLowReactive (pu or VAr): Minimum allowed reactive power output value at lowActive value.\nmaxLowReactive (pu or VAr): Maximum allowed reactive power output value at lowActive value.\nupActive (pu or W): Upper allowed active power output value of PQ capability curve.\nminUpReactive (pu or VAr): Minimum allowed reactive power output value at upActive value.\nmaxUpReactive (pu or VAr): Maximum allowed reactive power output value at upActive value.\nloadFollowing (pu/min or W/min): Ramp rate for load following/AG.\nreserve10min (pu or W): Ramp rate for 10-minute reserves.\nreserve30min (pu or W): Ramp rate for 30-minute reserves.\nreactiveRamp (pu/min or VAr/min): Ramp rate for reactive power, two seconds timescale.\narea: Area participation factor.\n\nUpdates\n\nThe function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nDefault Settings\n\nBy default, certain keywords are assigned default values: status = 1 and magnitude = 1.0 per-unit. The rest of the keywords are initialized with a value of zero. However, the user can modify these default settings by utilizing the @generator macro.\n\nUnits\n\nBy default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.\n\nExamples\n\nAdding a generator using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.2, base = 132e3)\n\naddGenerator!(system; bus = \"Bus 1\", active = 0.5, magnitude = 1.1)\n\nAdding a generator using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(kV, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 20, base = 132)\n\naddGenerator!(system; bus = \"Bus 1\", active = 50, magnitude = 145.2)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.updateGenerator!","page":"Power System Model","title":"JuliaGrid.updateGenerator!","text":"updateGenerator!(system::PowerSystem, [analysis::Analysis]; kwargs...)\n\nThe function allows for the alteration of parameters for an existing generator.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameter\n\nKeywords\n\nTo update a specific generator, provide the necessary kwargs input arguments in accordance with the keywords specified in the addGenerator! function, along with their respective values. Ensure that the label keyword matches the label of the existing generator you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the generator field within the PowerSystem composite type, and in cases where parameters impact variables in the bus field, it automatically adjusts the field. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addBranch! function.\n\nExample\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.2, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\nupdateGenerator!(system; label = \"Generator 1\", active = 0.6, reactive = 0.2)\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.cost!","page":"Power System Model","title":"JuliaGrid.cost!","text":"cost!(system::PowerSystem, [analysis::Analysis]; label, active, reactive,\n piecewise, polynomial)\n\nThe function either adds a new cost or modifies an existing one for the active or reactive power generated by the corresponding generator within the PowerSystem composite type. It has the capability to append a cost to an already defined generator.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the PowerSystem composite type only. However, when including the Analysis type, it updates both the PowerSystem and Analysis types. This streamlined approach circumvents the necessity for completely reconstructing vectors and matrices when adding a new branch.\n\nKeywords\n\nThe function accepts five keywords:\n\nlabel: Corresponds to the already defined generator label.\nactive: Active power cost model:\nactive = 1: adding or updating cost, and piecewise linear is being used,\nactive = 2: adding or updating cost, and polynomial is being used.\nreactive: Reactive power cost model:\nreactive = 1: adding or updating cost, and piecewise linear is being used,\nreactive = 2: adding or updating cost, and polynomial is being used.\npiecewise: Cost model defined by input-output points given as Matrix{Float64}:\nfirst column (pu, W or VAr): active or reactive power output of the generator,\nsecond column (€/hr): cost for the specified active or reactive power output.\npolynomial: The n-th degree polynomial coefficients given as Vector{Float64}:\nfirst element (€/puⁿ-hr, €/Wⁿhr or €/VArⁿ-hr): coefficient of the n-th degree term, ....,\npenultimate element (€/pu-hr, €/W-hr or €/VAr-hr): coefficient of the first degree term,\nlast element (€/hr): constant coefficient.\n\nUpdates\n\nThe function updates the generator.cost field within the PowerSystem composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nBy default, the input units related with active powers are per-units (pu), but they can be modified using the macro @power.\n\nExamples\n\nAdding a cost using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 0.25, reactive = -0.04, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5)\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.0; 500.0; 150.0])\n\nAdding a cost using a custom unit system:\n\n@power(MW, MVAr, MVA)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", active = 25, reactive = -4, base = 132e3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 50, reactive = 10)\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [0.11; 5.0; 150.0])\n\n\n\n\n\n","category":"function"},{"location":"api/powerSystemModel/#JuliaGrid.@generator","page":"Power System Model","title":"JuliaGrid.@generator","text":"@generator(kwargs...)\n\nThe macro generates a template for a generator, which can be utilized to define a generator using the addGenerator! function.\n\nKeywords\n\nTo define the generator template, the kwargs input arguments must be provided in accordance with the keywords specified within the addGenerator! function, along with their corresponding values.\n\nUnits\n\nBy default, the input units are associated with per-units (pu) as shown. However, users have the option to use other units instead of per-units using the @power and @voltage macros.\n\nExamples\n\nAdding a generator using the default unit system:\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 0.25, reactive = -0.04, base = 132e3)\n\n@generator(magnitude = 1.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.5, reactive = 0.1)\n\nAdding a generator using a custom unit system:\n\n@power(MW, MVAr, MVA)\n@voltage(kV, deg, kV)\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 2, active = 25, reactive = -4, base = 132)\n\n@generator(magnitude = 145.2)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 50, reactive = 10)\n\n\n\n\n\n","category":"macro"},{"location":"tutorials/dcPowerFlow/#DCPowerFlowTutorials","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid employs standard network components and the Unified Branch Model to obtain the DC power flow solution. To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7)\naddBus!(system; label = 3, type = 2, conductance = 0.07)\n\naddBranch!(system; from = 1, to = 2, reactance = 0.26)\naddBranch!(system; from = 1, to = 3, reactance = 0.38)\naddBranch!(system; from = 2, to = 3, reactance = 0.17, turnsRatio = 0.97)\n\naddGenerator!(system; bus = 1, active = 2.0)\naddGenerator!(system; bus = 1, active = 4.0)\naddGenerator!(system; bus = 3, active = 5.0)\nnothing #hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element associated with bus i in mathcalN, and a_ij represents the element associated with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#DCPowerFlowSolutionTutorials","page":"DC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"As discussed in section DC Model, the DC power flow problem can be represented by a set of linear equations:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" mathbf P = mathbfB bm Theta + mathbfP_texttr + mathbfP_textsh","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Implementation","page":"DC Power Flow","title":"Implementation","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid offers a set of functions to solve the DC power flow problem and obtain the bus voltage angles. Firstly, the power system is loaded and the DC model is built using the following code sequence:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The DC power flow solution is obtained through a non-iterative approach by solving the system of linear equations:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" bm Theta = mathbfB^-1(mathbf P - mathbfP_texttr - mathbfP_textsh)","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"JuliaGrid begins the process by establishing the DC power flow framework:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"analysis = dcPowerFlow(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The subsequent step involves performing the LU factorization of the nodal matrix mathbfB = mathbfLmathbfU and computing the bus voltage angles using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"tip: Tip\nBy default, JuliaGrid utilizes LU factorization as the primary method to factorize the nodal matrix. However, users maintain the flexibility to opt for alternative factorization methods such as LDLt or QR.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The factorization of the nodal matrix can be accessed using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"It is important to note that the slack bus voltage angle is excluded from the vector bmTheta only during the computation step. Consequently, the corresponding elements in the vectors mathbf P, mathbfP_texttr, mathbfP_textsh, and the corresponding row and column of the matrix mathbfB are removed. It is worth mentioning that this process is handled internally, and the stored elements remain unchanged.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, the resulting bus voltage angles are saved in the vector as follows:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#DCPowerAnalysisTutorials","page":"DC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution from the DC power flow, we can calculate powers related to buses, branches, and generators using the power! function:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Power-Injections","page":"DC Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Generator-Power-Injections","page":"DC Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The active power supplied by generators to the buses can be calculated by summing the given generator active powers in the input data, except for the slack bus, which can be determined as:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" P_textpi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"where P_textdi represents the active power demanded by consumers at the slack bus. The vector of active powers injected by generators into the buses, denoted by mathbfP_textp = P_textpi, can be obtained using the following command:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Power-Flows","page":"DC Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The resulting from-bus active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Similarly, the resulting to-bus active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"tutorials/dcPowerFlow/#Generators-Power-Outputs","page":"DC Power Flow","title":"Generators Power Outputs","text":"","category":"section"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The output active power of each generator located at bus i in mathcalN_textpv cup mathcalN_textpq is equal to the active power specified in the input data. If there are multiple generators, their output active powers are also equal to the active powers specified in the input data. However, the output active power of a generator located at the slack bus will be:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":" P_textgi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In the case of multiple generators connected to the slack bus, the first generator in the input data is assigned the obtained value of P_textgi. Then, this amount of power is reduced by the output active power of the other generators.","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To retrieve the vector of active power outputs of generators, denoted as mathbfP_textg = P_textgi, i in mathcalS, where the set mathcalS represents the set of generators, users can utilize the following command:","category":"page"},{"location":"tutorials/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowTutorials","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, Ipopt\n@default(unit) # hide\n@default(template) # hide\n\n@labels(Integer)\n\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.95, maxMagnitude = 1.05)\naddBus!(system; label = 1, type = 3, active = 0.1, angle = -0.1)\naddBus!(system; label = 2, reactive = 0.01, magnitude = 1.1)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, reactance = 0.5, type = 2)\naddBranch!(system; label = 1, from = 1, to = 2, maxFromBus = 0.15, maxToBus = 0.15)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1)\naddGenerator!(system; label = 1, bus = 1, active = 0.4, reactive = 0.2)\naddGenerator!(system; label = 2, bus = 2, active = 0.2, reactive = 0.1)\n\ncost!(system; label = 1, active = 2, polynomial = [900.0; 500.0; 80.0; 5.0])\ncost!(system; label = 2, active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\ncost!(system; label = 1, reactive = 1, piecewise = [10.0 20.0; 20.0 40.0])\ncost!(system; label = 2, reactive = 2, polynomial = [2.0])\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Moreover, we identify the set of generators as mathcalS = 1 dots n_textg within the power system:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝒮 = collect(keys(system.generator.label))","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or generator i in mathcalS, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowModelTutorials","page":"AC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow model, the active and reactive power outputs of the generators, denoted as mathbf P_textg = P_textgi and mathbf Q_textg = Q_textgi, where i in mathcalS, are expressed as nonlinear functions of the bus voltage magnitudes and angles, denoted as mathbf V = V_i and bmTheta = theta_i, where i in mathcalN. Consequently, the optimization variables encompass the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The AC optimal power flow problem can be formulated as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n textminimize sum_i in mathcalS left f_i(P_textgi) + f_i(Q_textgi) right \n textsubjectto theta_i - theta_texts = 0 i in mathcalN_textsb 5pt\n h_P_i(mathbf P_textg mathbf V bmTheta) = 0 forall i in mathcalN \n h_Q_i(mathbf Q_textg mathbf V bmTheta) = 0 forall i in mathcalN 5pt\n V_i^textmin leq V_i leq V_i^textmax forall i in mathcalN \n theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE 5pt\n F_ij^textmin leq h_ij(mathbf V bmTheta) leq F_ij^textmax forall (ij) in mathcalE \n F_ji^textmin leq h_ji(mathbf V bmTheta) leq F_ji^textmax forall (ij) in mathcalE 5pt\n P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS \n Q_textgi^textmin leq Q_textgi leq Q_textgi^textmax forall i in mathcalS\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In essence, the AC optimal power flow aims to minimize the objective function associated with the costs of generator's active and reactive power output while ensuring the fulfillment of all constraints. This optimization task plays a pivotal role in effectively managing electrical power systems. By striking a balance between cost reduction and constraint adherence, the AC optimal power flow contributes to efficient and reliable electricity supply in complex grid environments.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Build-Optimal-Power-Flow-Model","page":"AC Optimal Power Flow","title":"Build Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To build the AC optimal power flow model, we must first load the power system and establish the AC model:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"acModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Afterward, the AC optimal power flow model is created using the acOptimalPowerFlow function:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(\n system, Ipopt.Optimizer; active = \"Pg\", reactive = \"Qg\", magnitude = \"V\", angle = \"θ\"\n)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Optimization-Variables","page":"AC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The variables within this model encompass the active and reactive power outputs of the generators, denoted as mathbfP_textg = P_textgi and mathbfQ_textg = Q_textgi, where i in mathcalS, and the bus voltage magnitudes and angles represented by mathbfV = V_i and bmTheta = theta_i, where i in mathcalN. We can access these variables using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = analysis.method.variable.active\n𝐐ₒ = analysis.method.variable.reactive\n𝐕 = analysis.method.variable.magnitude\n𝚯 = analysis.method.variable.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Objective-Function","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The objective function represents the sum of the active and reactive power cost functions f_i(P_textgi) and f_i(Q_textgi), where i in mathcalS, for each generator, where these cost functions can be polynomial or linear piecewise. Typically, the AC optimal power flow focuses on minimizing the cost of active power outputs only, but for comprehensive analysis, we also consider the costs associated with reactive power outputs.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Polynomial-Cost-Function","page":"AC Optimal Power Flow","title":"Polynomial Cost Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the following analysis, we will focus on the cost function of generating active power, denoted as f_i(P_textgi). However, please note that the same analysis can be applied to the cost function f_i(Q_textgi) for reactive power.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow, the cost function f_i(P_textgi) can be represented as an n-th degree polynomial:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f_i(P_textgi) = sum_k=0^n a_k P_textgi^k","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Typically, cost functions are represented as linear, quadratic, or cubic, as shown in Figure 1:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n f_i(P_textgi) = a_1P_textgi + a_0 \n f_i(P_textgi) = a_2 P_textgi^2 + a_1P_textgi + a_0 \n f_i(P_textgi) = a_3 P_textgi^3 + a_2 P_textgi^2 + a_1P_textgi + a_0 \nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 1: The polynomial cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When using the cost! function in JuliaGrid and specifying the polynomial keyword, the polynomial is constructed with coefficients arranged in descending order of their degrees, from the highest degree to the lowest. For example, in the case study provided, we generated a cubic polynomial cost function for the active output power of Generator 1, which is represented as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n f_1(P_textg1) = 900 P_textg1^3 + 500 P_textg1^2 + 80 P_textg1 + 5\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these coefficients, users can utilize the variable:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f₁ = system.generator.cost.active.polynomial[1]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Linear-Piecewise-Cost-Function","page":"AC Optimal Power Flow","title":"Linear Piecewise Cost Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second option for defining cost functions in the AC optimal power flow is to use linear piecewise functions as approximations of the polynomial functions, as illustrated in Figure 2.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 2: The linear piecewise cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To define linear piecewise functions in JuliaGrid, users can utilize the cost! function with the piecewise keyword. The linear piecewise function is constructed using a matrix where each row defines a single point. The first column holds the generator's active or reactive power output, while the second column corresponds to the associated cost value. For example, in the provided case study, a linear piecewise function is created and can be accessed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"f₂ = system.generator.cost.active.piecewise[2]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid handles convex linear piecewise functions using a constrained cost variable method. In this approach, the piecewise linear cost function is replaced by a helper variable and a set of linear inequality constraints for each segment of the function defined by two neighboring points along the line. However, for linear piecewise functions that have only one segment defined by two points, JuliaGrid transforms it into a standard linear function without introducing a helper variable.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Hence, for a piecewise cost function denoted as f_i(P_textgi) with k segments (where k 1), the j-th segment, defined by the points P_textgij f_i(P_textgij) and P_textgij+1 f_i(P_textgij+1), is characterized by the following inequality constraints:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"cfracf_i(P_textgij+1) - f_i(P_textgij)P_textgij+1 - P_textgij(P_textgi - P_textgij) + f_i(P_textgij) leq H_i i in mathcalS j = 1dotsk","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where H_i represents the helper variable. To finalize this method, we simply need to include the helper variable H_i in the objective function. This approach efficiently handles linear piecewise cost functions, providing the flexibility to capture nonlinear characteristics while still benefiting from the advantages of linear optimization techniques.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As an example, in the provided case study, the helper variable is defined as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"H₂ = analysis.method.variable.actwise[2]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Lastly, the set of constraints introduced by the linear piecewise cost function is displayed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.piecewise.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Objective-Function-2","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As previously explained, the objective function relies on the defined polynomial or linear piecewise cost functions and represents the sum of these costs. In the provided example, the objective function that must be minimized to obtain the optimal values for the active and reactive power outputs of the generators and the bus voltage magnitudes and angles can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Constraint-Functions","page":"AC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the following section, we will examine the various constraints defined within the AC optimal power flow model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Slack-Bus-Constraint","page":"AC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The first equality constraint is linked to the slack bus, where the bus voltage angle denoted as theta_i is fixed to a constant value theta_texts. It can be expressed as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"theta_i - theta_texts = 0 i in mathcalN_textsb","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where the set mathcalN_textsb contains the index of the slack bus. To access the equality constraint from the model, we can utilize the variable:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.slack.angle)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Bus-Power-Balance-Constraints","page":"AC Optimal Power Flow","title":"Bus Power Balance Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second equality constraint in the optimization problem is associated with the active power balance equation:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\nh_P_i(mathbf P_textg mathbf V bmTheta) = 0 forall i in mathcalN\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As elaborated in the Bus Injections section, we can express the equation as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"h_P_i(mathbf P_textg mathbf V bmTheta) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - sum_k in mathcalS_i P_textgk + P_textdi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this equation, the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN, and P_textgk represents the active power output of the k-th generator within the set mathcalS_i. More Precisely, the variable P_textgk represents the optimization variable, along with the bus voltage angles theta_ij = theta_i - theta_j and the bus voltage magnitudes V_i and V_j.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term is determined by the active power demand P_textdi at bus i in mathcalN. The values representing this constant term, denoted as mathbfP_textd = P_textdi, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = system.bus.demand.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can access the references to the active power balance constraints using the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.balance.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the next constraint in the optimization problem is associated with the reactive power balance equation:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\nh_Q_i(mathbf Q_textg mathbf V bmTheta) = 0 forall i in mathcalN\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As elaborated in the Bus Injections section, we can express the equation as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"h_Q_i(mathbf Q_textg mathbf V bmTheta) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - sum_k in mathcalS_i Q_textgk + Q_textdi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As mentioned earlier for active power, Q_textgk represents the reactive power output of the k-th generator within the set mathcalS_i. The variable Q_textgk serves as an optimization variable, as well as the bus voltage angles theta_ij = theta_i - theta_j, and the bus voltage magnitudes V_i and V_j.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term is determined by the reactive power demand Q_textdi at bus i in mathcalN. The values representing this constant term, denoted as mathbfQ_textd = Q_textdi, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₒ = system.bus.demand.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can access the references to the reactive power balance constraints using the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.balance.reactive)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Bus-Voltage-Constraints","page":"AC Optimal Power Flow","title":"Bus Voltage Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraints associated with the voltage magnitude ensure that the bus voltage magnitudes are within specified limits:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"V_i^textmin leq V_i leq V_i^textmax forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where V_i^textmin represents the minimum voltage magnitude, and V_i^textmax represents the maximum voltage magnitude for bus i in mathcalN. The values representing these voltage magnitude limits, denoted as mathbfV_textlm = V_i^textmin V_i^textmax, i in mathcalN, can be accessed using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐕ₗₘ = [system.bus.voltage.minMagnitude system.bus.voltage.maxMagnitude]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To retrieve this inequality constraint from the model, we can use the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.magnitude)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraint related to the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch is defined as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where theta_ij^textmin represents the minimum, while theta_ij^textmax represents the maximum of the angle difference between adjacent buses. The values representing the voltage angle difference, denoted as bmTheta_textlm = theta_ij^textmin theta_ij^textmax, (ij) in mathcalE, are provided as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝚯ₗₘ = [system.branch.voltage.minDiffAngle system.branch.voltage.maxDiffAngle]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To retrieve this inequality constraint from the model, we can use the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.angle)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Branch-Flow-Constraints","page":"AC Optimal Power Flow","title":"Branch Flow Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The inequality constraints related to the branch flow ratings can be associated with the limits on apparent power flow, active power flow, or current magnitude at the from-bus and to-bus ends of each branch. The type of constraint applied is determined by the type keyword within the addBranch! function.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Specifically, type = 1 is used for apparent power flow, type = 2 for active power flow, and type = 3 for current magnitude. These constraints can be expressed using the equations h_ij(mathbf V bmTheta) and h_ji(mathbf V bmTheta), representing the rating constraints at the from-bus and to-bus ends of each branch, respectively:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n F_ij^textmin leq h_ij(mathbf V bmTheta) leq F_ij^textmax forall (ij) in mathcalE \n F_ji^textmin leq h_ji(mathbf V bmTheta) leq F_ji^textmax forall (ij) in mathcalE\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The branch flow limits at the from-bus and to-bus ends, denoted as mathbfF_textf = F_ij^textmin F_ij^textmax and mathbfF_textt = F_ji^textmin F_ji^textmax, (ij) in mathcalE, can be retrieved as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐅ₒ = [system.branch.flow.minFromBus system.branch.flow.maxFromBus]\n𝐅ₜ = [system.branch.flow.minToBus system.branch.flow.maxToBus]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By default, JuliaGrid employs the rating constraints linked with the apparent power flow (type = 1). This constraint at the from-bus is specified as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" h_ij(mathbf V bmTheta) = sqrt A_ij V_i^4 + B_ij V_i^2 V_j^2 - 2 C_ij cos(theta_ij - phi_ij) - D_ij sin(theta_ij - phi_ij)V_i^3 V_j","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" begingathered\n A_ij = cfrac(g_ij + g_textsi)^2+(b_ij+b_textsi)^2tau_ij^4 B_ij = cfracg_ij^2+b_ij^2tau_ij^2 \n C_ij = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij^3 D_ij = cfracg_ijb_textsi - b_ijg_textsitau_ij^3\n endgathered","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Furthermore, this constraint at the to-bus is specified as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" h_ji(mathbf V bmTheta) = sqrt A_ji V_j^4 + B_ji V_i^2 V_j^2 - 2 C_ji cos(theta_ij - phi_ij) + D_ij sin(theta_ij - phi_ij)V_i V_j^3 ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" begingathered\n A_ji = (g_ij + g_textsi)^2+(b_ij+b_textsi)^2 B_ji = cfracg_ij^2+b_ij^2tau_ij^2 \n C_ji = cfracg_ij(g_ij+g_textsi)+b_ij(b_ij+b_textsi)tau_ij D_ji = cfracg_ijb_textsi - b_ijg_textsitau_ij\n endgathered","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The second option is to define the limit keywords for active power flow constraints (type = 2) at the from-bus and to-bus ends of each branch:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" beginaligned\n h_ij(mathbf V bmTheta) =\n cfrac g_ij + g_textsijtau_ij^2 V_i^2 -\n cfrac1tau_ij leftg_ijcos(theta_ij - phi_ij) + b_ijsin(theta_ij - phi_ij)rightV_iV_j \n h_ji(mathbf V bmTheta) = (g_ij + g_textsij) V_j^2 -\n cfrac1tau_ij leftg_ij cos(theta_ij - phi_ij) - b_ij sin(theta_ij- phi_ij)right V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In our example, we have chosen to utilize this type of flow constraints. To access the flow constraints of branches at the from-bus end, you can use the following code snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.flow.from)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, to access the to-bus end flow constraints of branches you can use the following code snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.flow.to)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The last option involves defining the limit keywords for current magnitude constraints (type = 3) at the from-bus and to-bus ends of each branch. In this case, the constraints are implemented as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" beginaligned\n h_ij(mathbf V bmTheta) = sqrtA_ijV_i^2 + B_ijV_j^2 - 2C_ij cos(theta_ij - phi_ij) - D_ijsin(theta_ij - phi_ij)V_iV_j \n h_ji(mathbf V bmTheta) = sqrtA_jiV_j^2 + B_jiV_i^2 - 2C_ji cos(theta_ij - phi_ij) + D_jisin(theta_ij - phi_ij)V_iV_j\n endaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACPowerCapabilityConstraintsTutorials","page":"AC Optimal Power Flow","title":"Generator Power Capability Constraints","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The next set of constraints pertains to the minimum and maximum limits of active and reactive power outputs of the generators. These constraints ensure that the power outputs of the generators remain within specified bounds:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this representation, the lower and upper limits are determined by the vector mathbfP_textm = P_textgi^textmin P_textgi^textmax, i in mathcalS. We can access these bounds using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₘ = [system.generator.capability.minActive, system.generator.capability.maxActive]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these constraints, you can utilize the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.capability.active)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, constraints related to the minimum and maximum limits of reactive power outputs of the generators ensure that the reactive powers remain within specified boundaries:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Q_textgi^textmin leq Q_textgi leq Q_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Thus, the lower and upper limits are determined by the vector mathbfQ_textm = Q_textgi^textmin Q_textgi^textmax, i in mathcalS. We can access these bounds using the following:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₘ = [system.generator.capability.minReactive system.generator.capability.maxReactive]","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To access these constraints, you can use the following snippet:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(analysis.method.constraint.capability.reactive)","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These capability limits of the generators define the feasible region, represented as a gray area in Figure 3, which forms the solution space for the active and reactive output powers of the generators.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 3: The feasible region created by the active and reactive power capability constraints.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"However, this representation might not be the most accurate depiction of the generator's output power behavior. In reality, there exists a tradeoff between the active and reactive power outputs of the generators [8]. Specifically, when a generator operates at its maximum active power P_textgi^textmax, it may not be able to produce the maximum Q_textgi^textmax or minimum Q_textgi^textmin reactive power. To capture this tradeoff, we introduce the ability to include additional upper and lower constraints on the feasible region, leading to its reduction as shown in Figure 4.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"\n
Figure 4: The feasible region created by the active and reactive power capability constraints with additional upper and lower constraints.
\n ","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"If a user wishes to incorporate the tradeoff between active and reactive power outputs into the optimization model, they can define the points shown in Figure 4 within the addGenerator! function using the following keywords:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Keyword Coordinate\nlowActive P_textgi^textlow\nminLowReactive Q_textgitextlow^textmin\nmaxLowReactive Q_textgitextlow^textmax\nupActive P_textgi^textup\nminUpReactive Q_textgitextup^textmin\nmaxUpReactive Q_textgitextup^textmax","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When using these points, JuliaGrid constructs two additional capability constraints per generator as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n (Q_textgitextlow^textmax - Q_textgitextup^textmax)P_textgi + (P_textgi^textup - P_textgi^textlow)Q_textgi\n leq (Q_textgitextlow^textmax - Q_textgitextup^textmax)P_textgi^textlow + (P_textgi^textup - P_textgi^textlow)Q_textgitextlow^textmax \n (Q_textgitextup^textmin - Q_textgitextlow^textmin)P_textgi + (P_textgi^textlow - P_textgi^textup)Q_textgi\n leq (Q_textgitextup^textmin - Q_textgitextlow^textmin)P_textgi^textlow + (P_textgi^textlow - P_textgi^textup)Q_textgitextlow^textmin\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To ensure numerical stability, these constraints are normalized by introducing two scaling factors:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"beginaligned\n s_1 = sqrt(Q_textgitextlow^textmax - Q_textgitextup^textmax)^2 + (P_textgi^textup - P_textgi^textlow)^2\n s_2 = sqrt(Q_textgitextup^textmin - Q_textgitextlow^textmin)^2 + (P_textgi^textlow - P_textgi^textup)^2\nendaligned","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"When these constraints exist in the system, users can access them using the following variables:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.constraint.capability.upper\nanalysis.method.constraint.capability.lower\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These additional capability constraints allow us to accurately represent the tradeoff between active and reactive power outputs of the generators while maintaining numerical stability.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerFlowSolutionTutorials","page":"AC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the optimal values of active and reactive power outputs for generators and the bus voltage magnitudes and angles, the user needs to invoke the following function:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After solving the AC optimal power flow problem, you can retrieve the vectors of output active and reactive power for generators, denoted as mathbfP_textg = P_textgi and mathbfQ_textg = Q_textgi, where i in mathcalS, using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₒ = analysis.power.generator.active\n𝐐ₒ = analysis.power.generator.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the resulting bus voltage magnitudes and angles, represented by mathbfV = V_i and bmTheta = theta_i, where i in mathcalN, are stored in the vectors as follows:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By accessing these vectors, you can analyze and utilize the optimal power flow solution for further studies or operational decision-making in the power system.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#ACOptimalPowerAnalysisTutorials","page":"AC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses and branches:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-Injections","page":"AC Optimal Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#OptGeneratorPowerInjectionsManual","page":"AC Optimal Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The power! function in JuliaGrid also provides the computation of active and reactive power injections from the generators at each bus. To calculate the active power supplied by generators to the buses, one can simply sum the active power outputs of the generators obtained from the AC optimal power flow. This can be represented as:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" P_textpi = sum_k in mathcalS_i P_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"where the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN. The active power injections from the generators at each bus are stored as a vector denoted by mathbfP_textp = P_textpi, and can be obtained using:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can obtain the reactive power supplied by generators to the buses:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":" Q_textpi = sum_k in mathcalS_i Q_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The vector of these reactive power injections by the generators to the buses, denoted by mathbfQ_textp = Q_textpi, can be retrieved using the following command:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Bus-Shunt-Elements","page":"AC Optimal Power Flow","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-Flows","page":"AC Optimal Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Branch-Shunt-Elements","page":"AC Optimal Power Flow","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Power-at-Branch-Series-Elements","page":"AC Optimal Power Flow","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Analysis","page":"AC Optimal Power Flow","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Injections","page":"AC Optimal Power Flow","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-Flows","page":"AC Optimal Power Flow","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/acOptimalPowerFlow/#Current-at-Branch-Series-Elements","page":"AC Optimal Power Flow","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"api/measurementModel/#measurementModelAPI","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For further information on this topic, please see the Measurement Model section of the Manual. Below, we have provided a list of functions that can be used to create, save, and manipulate with measurement devices.","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To load measurement model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Measurement-Data","page":"Measurement Model","title":"Measurement Data","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement\nsaveMeasurement\nstatus!","category":"page"},{"location":"api/measurementModel/#Voltmeter","page":"Measurement Model","title":"Voltmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!\nupdateVoltmeter!\nstatusVoltmeter!\n@voltmeter","category":"page"},{"location":"api/measurementModel/#Ammeter","page":"Measurement Model","title":"Ammeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!\nupdateAmmeter!\nstatusAmmeter!\n@ammeter","category":"page"},{"location":"api/measurementModel/#Wattmeter","page":"Measurement Model","title":"Wattmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!\nupdateWattmeter!\nstatusWattmeter!\n@wattmeter","category":"page"},{"location":"api/measurementModel/#Varmeter","page":"Measurement Model","title":"Varmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!\nupdateVarmeter!\nstatusVarmeter!\n@varmeter","category":"page"},{"location":"api/measurementModel/#PMU","page":"Measurement Model","title":"PMU","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!\nupdatePmu!\nstatusPmu!\n@pmu","category":"page"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Measurement-Data-2","page":"Measurement Model","title":"Measurement Data","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement\nsaveMeasurement\nstatus!","category":"page"},{"location":"api/measurementModel/#JuliaGrid.measurement","page":"Measurement Model","title":"JuliaGrid.measurement","text":"measurement(file::String)\n\nThe function builds the composite type Measurement and populates voltmeter, ammeter, wattmeter, varmeter, and pmu fields. In general, once the composite type Measurement has been created, it is possible to add new measurement devices, or modify the parameters of existing ones.\n\nArgument\n\nIt requires a string path to the HDF5 file with the .h5 extension.\n\nReturns\n\nThe Measurement composite type with the following fields:\n\nvoltmeter: Bus voltage magnitude measurements.\nammeter: Branch current magnitude measurements.\nwattmeter: Active power injection and active power flow measurements.\nvarmeter: Reactive power injection and reactive power flow measurements.\npmu: Bus voltage and branch current phasor measurements.\n\nUnits\n\nJuliaGrid stores all data in per-units and radians format.\n\nExample\n\ndevice = measurement(\"measurement14.h5\")\n\n\n\n\n\nmeasurement()\n\nAlternatively, the Measurement composite type can be initialized by calling the function without any arguments. This allows the model to be built from scratch and modified as needed.\n\nExample\n\ndevice = measurement()\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.saveMeasurement","page":"Measurement Model","title":"JuliaGrid.saveMeasurement","text":"saveMeasurement(device::Measurement; path::String, reference::String, note::String)\n\nThe function saves the measurement's data in the HDF5 file using the fields voltmeter, ammeter, wattmeter, varmeter, and pmu from the Measurement composite type.\n\nKeywords\n\nThe location and file name of the HDF5 file is specified by the mandatory keyword path in the format of \"path/name.h5\". Additional information can be provided by the optional keywords reference and note, which can be saved along with the power system data.\n\nView HDF5 File\n\nTo view the saved HDF5 file, you can use the HDFView software.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.m\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\n\nsaveMeasurement(device; path = \"D:/measurement14.h5\")\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.status!","page":"Measurement Model","title":"JuliaGrid.status!","text":"status!(system::PowerSystem, device::Measurement; inservice, outservice, redundancy)\n\nThe function generates a set of measurements, assigning measurement devices randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nOnly one of the following keywords can be used at a time to configure the measurement set:\n\ninservice: Sets the number of in-service devices.\noutservice: Sets the number of out-of-service devices.\nredundancy: Determines in-service devices based on redundancy.\n\nUpdates\n\nThe function updates all the status fields within the Measurement type.\n\nExamples\n\nCreating a measurement set with a specific number of in-service devices:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\n\nstatus!(system, device; inservice = 30)\n\nCreating a measurement set using redundancy:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddWattmeter!(system, device, analysis)\naddVarmeter!(system, device, analysis)\n\nstatus!(system, device; redundancy = 2.5)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Voltmeter-2","page":"Measurement Model","title":"Voltmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!(::PowerSystem, ::Measurement)\naddVoltmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateVoltmeter!\nstatusVoltmeter!\n@voltmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addVoltmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addVoltmeter!","text":"addVoltmeter!(system::PowerSystem, device::Measurement; label, bus, magnitude, variance,\n noise, status)\n\nThe function adds a new voltmeter that measures bus voltage magnitude to the Measurement type within a given PowerSystem type. The voltmeter can be added to an already defined bus.\n\nKeywords\n\nThe voltmeter is defined with the following keywords:\n\nlabel: Unique label for the voltmeter.\nbus: Label of the bus to which the voltmeter is connected.\nmagnitude (pu or V): Bus voltage magnitude value.\nvariance (pu or V): Variance of the bus voltage magnitude measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitude,\nnoise = false: uses the magnitude value only.\nstatus: Operating status of the voltmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the voltmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, and users can modify these default settings using the @voltmeter macro.\n\nUnits\n\nThe default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExamples\n\nAdding a voltmeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.1)\n\nAdding a voltmeter using a custom unit system:\n\n@voltage(kV, rad, kV)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 145.2)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addVoltmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addVoltmeter!","text":"addVoltmeter!(system::PowerSystem, device::Measurement, analysis::AC; variance, noise,\n status)\n\nThe function incorporates voltmeters into the Measurement composite type for every bus within the PowerSystem type. These measurements are derived from the exact bus voltage magnitudes defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvariance (pu or V): Variance of bus voltage magnitude measurements.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the voltage magnitudes,\nnoise = false: uses the exact voltage magnitude values.\nstatus: Operating status of the voltmeters:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the voltmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: variance = 1e-2, noise = false, and status = 1, and users can modify these default settings using the @voltmeter macro.\n\nUnits\n\nBy default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\n@voltmeter(label = \"Voltmeter ?\")\naddVoltmeter!(system, device, analysis; variance = 1e-3, noise = true)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateVoltmeter!","page":"Measurement Model","title":"JuliaGrid.updateVoltmeter!","text":"updateVoltmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a voltmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific voltmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVoltmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing voltmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the voltmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addVoltmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.1)\nupdateVoltmeter!(system, device; label = \"Voltmeter 1\", magnitude = 0.9)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusVoltmeter!","page":"Measurement Model","title":"JuliaGrid.statusVoltmeter!","text":"statusVoltmeter!(system::PowerSystem, device::Measurement; inservice, outservice,\n redundancy)\n\nThe function generates a set of voltmeters, assigning voltmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nOnly one of the following keywords can be used at a time to configure the measurement set:\n\ninservice: Sets the number of in-service voltmeters.\noutservice: Sets the number of out-of-service voltmeters.\nredundancy: Determines in-service voltmeters based on redundancy.\n\nUpdates\n\nThe function updates the status field within the Voltmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\n\naddVoltmeter!(system, device, analysis)\nstatusVoltmeter!(system, device; inservice = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@voltmeter","page":"Measurement Model","title":"JuliaGrid.@voltmeter","text":"@voltmeter(label, variance, noise, status)\n\nThe macro generates a template for a voltmeter, which can be utilized to define a voltmeter using the addVoltmeter! function.\n\nKeywords\n\nTo establish the voltmeter template, users can specify default values for the variance, noise, and status keywords, along with pattern for labels using the label keyword.\n\nUnits\n\nBy default, the unit for variance is per-unit (pu). However, users can choose to use volts (V) as the units by applying the @voltage macro.\n\nExamples\n\nAdding a voltmeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\n@voltmeter(label = \"Voltmeter ?\", variance = 1e-5)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.1)\n\nAdding a voltmeter using a custom unit system:\n\n@voltage(kV, rad, kV)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\n\n@voltmeter(label = \"Voltmeter ?\", variance = 0.00132)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 145.2)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Ammeter-2","page":"Measurement Model","title":"Ammeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(::PowerSystem, ::Measurement)\naddAmmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateAmmeter!\nstatusAmmeter!\n@ammeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addAmmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addAmmeter!","text":"addAmmeter!(system::PowerSystem, device::Measurement; label, from, to, magnitude,\n variance, noise, status)\n\nThe function adds a new ammeter that measures branch current magnitude to the Measurement type within a given PowerSystem type. The ammeter can be added to an already defined branch.\n\nKeywords\n\nThe ammeter is defined with the following keywords:\n\nlabel: Unique label for the ammeter.\nfrom: Label of the branch if the ammeter is located at the from-bus end.\nto: Label of the branch if the ammeter is located at the to-bus end.\nmagnitude (pu or A): Branch current magnitude value.\nvariance (pu or A): Variance of the branch current magnitude measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitude,\nnoise = false: uses the magnitude value only.\nstatus: Operating status of the ammeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the ammeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, status = 1, which apply to ammeters located at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for ammeters positioned on either the from-bus or to-bus ends of branches using the @ammeter macro.\n\nUnits\n\nThe default units for the magnitude and variance keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExamples\n\nAdding ammeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 1.0)\n\nAdding ammeters using a custom unit system:\n\n@current(A, rad)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 481.125)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 437.386)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addAmmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addAmmeter!","text":"addAmmeter!(system::PowerSystem, device::Measurement, analysis::AC; varianceFrom,\n statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates ammeters into the Measurement type for every branch within the PowerSystem type. These measurements are derived from the exact branch current magnitudes defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceFrom (pu or A): Measurement variance for ammeters at the from-bus ends.\nstatusFrom: Operating status of the ammeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or A): Measurement variance for ammeters at the to-bus ends.\nstatusTo: Operating status of the ammeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the current magnitudes,\nnoise = false: uses the exact current magnitude values.\n\nUpdates\n\nThe function updates the ammeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @ammeter macro.\n\nUnits\n\nThe default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\n@ammeter(label = \"Ammeter ?\")\naddAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateAmmeter!","page":"Measurement Model","title":"JuliaGrid.updateAmmeter!","text":"updateAmmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for an ammeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific ammeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addAmmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing ammeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the ammeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addAmmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\nupdateAmmeter!(system, device; label = \"Ammeter 1\", magnitude = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusAmmeter!","page":"Measurement Model","title":"JuliaGrid.statusAmmeter!","text":"statusAmmeter!(system::PowerSystem, ammeter::Ammeter; inservice, inserviceFrom,\n inserviceTo, outservice, outserviceFrom, outserviceTo, redundancy, redundancyFrom,\n redundancyTo)\n\nThe function generates a set of ammeters, assigning ammeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or two fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service ammeters or allows fine-tuning:\ninserviceFrom: sets only ammeters loacted at the from-bus end,\ninserviceTo: sets only ammeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service ammeters or allows fine-tuning:\noutserviceFrom: sets only ammeters loacted at the from-bus end,\noutserviceTo: sets only ammeters loacted at the to-bus end.\nredundancy: Determines in-service ammeters based on redundancy or allows fine-tuning:\nredundancyFrom: determines only ammeters loacted at the from-bus end,\nredundancyTo: determines only ammeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Ammeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\naddAmmeter!(system, device, analysis)\nstatusAmmeter!(system, device; inserviceFrom = 5, inserviceTo = 10)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@ammeter","page":"Measurement Model","title":"JuliaGrid.@ammeter","text":"@ammeter(label, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe macro generates a template for an ammeter, which can be utilized to define an ammeter using the addAmmeter! function.\n\nKeywords\n\nTo establish the ammeter template, users can set default variance and status values for ammeters at both the from-bus and to-bus ends of branches, using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceFrom and varianceTo keywords are per-units (pu). However, users can choose to use amperes (A) as the units by applying the @current macro.\n\nExamples\n\nAdding an ammeter using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@ammeter(label = \"Ammeter ?\", varianceTo = 1e-3, statusTo = 0)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 1.1)\n\nAdding an ammeter using a custom unit system:\n\n@current(A, rad)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@ammeter(label = \"Ammeter ?\", varianceTo = 0.004374, statusTo = 0)\naddAmmeter!(system, device; label = \"Ammeter 1\", to = \"Branch 1\", magnitude = 481.125)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Wattmeter-2","page":"Measurement Model","title":"Wattmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(::PowerSystem, ::Measurement)\naddWattmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateWattmeter!\nstatusWattmeter!\n@wattmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addWattmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addWattmeter!","text":"addWattmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, active,\n variance, noise, status)\n\nThe function adds a new wattmeter that measures active power injection or active power flow to the Measurement type within a given PowerSystem type. The wattmeter can be added to an already defined bus or branch.\n\nKeywords\n\nThe wattmeter is defined with the following keywords:\n\nlabel: Unique label for the wattmeter.\nbus: Label of the bus if the wattmeter is located at the bus.\nfrom: Label of the branch if the wattmeter is located at the from-bus end.\nto: Label of the branch if the wattmeter is located at the to-bus end.\nactive (pu or W): Active power value.\nvariance (pu or W): Variance of the active power measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the active,\nnoise = false: uses the active value only.\nstatus: Operating status of the wattmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the wattmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to wattmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for wattmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @wattmeter macro.\n\nUnits\n\nThe default units for the active and variance keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExamples\n\nAdding wattmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 2\", active = 0.4)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 0.1)\n\nAdding wattmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 2\", active = 40.0)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 10.0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addWattmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addWattmeter!","text":"addWattmeter!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates wattmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact active power injections at buses and active power flows in branches defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceBus (pu or W): Measurement variance for wattmeters at the buses.\nstatusBus: Operating status of the wattmeters at the buses:\nstatusBus = 1: in-service,\nstatusBus = 0: out-of-service.\nvarianceFrom (pu or W): Measurement variance for wattmeters at the from-bus ends.\nstatusFrom: Operating status of the wattmeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or W): Measurement variance for wattmeters at the to-bus ends.\nstatusTo: Operating status of the wattmeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the active powers,\nnoise = false: uses the exact active power values.\n\nUpdates\n\nThe function updates the wattmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @wattmeter macro.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateWattmeter!","page":"Measurement Model","title":"JuliaGrid.updateWattmeter!","text":"updateWattmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a wattmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific wattmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addWattmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing wattmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the wattmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addWattmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddWattmeter!(system, device; label = \"Wattmeter 1\", from = \"Branch 1\", active = 1.1)\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", active = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusWattmeter!","page":"Measurement Model","title":"JuliaGrid.statusWattmeter!","text":"statusWattmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of wattmeters, assigning wattmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service wattmeters or allows fine-tuning:\ninserviceBus: sets only wattmeters loacted at the bus,\ninserviceFrom: sets only wattmeters loacted at the from-bus end,\ninserviceTo: sets only wattmeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service wattmeters or allows fine-tuning:\noutserviceBus: sets only wattmeters loacted at the bus,\noutserviceFrom: sets only wattmeters loacted at the from-bus end,\noutserviceTo: sets only wattmeters loacted at the to-bus end.\nredundancy: Determines in-service wattmeters based on redundancy or allows fine-tuning:\nredundancyBus: determines only wattmeters loacted at the bus,\nredundancyFrom: determines only wattmeters loacted at the from-bus end,\nredundancyTo: determines only wattmeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Wattmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddWattmeter!(system, device, analysis)\nstatusWattmeter!(system, device; outserviceBus = 14, inserviceFrom = 10, outserviceTo = 2)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@wattmeter","page":"Measurement Model","title":"JuliaGrid.@wattmeter","text":"@wattmeter(label, varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo,\n noise)\n\nThe macro generates a template for a wattmeter, which can be utilized to define a wattmeter using the addWattmeter! function.\n\nKeywords\n\nTo establish the wattmeter template, users can set default variance and status values for wattmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use watts (W) as the units by applying the @power macro.\n\nExamples\n\nAdding wattmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@wattmeter(label = \"Wattmeter ?\", varianceBus = 1e-3, varianceFrom = 1e-4)\naddWattmeter!(system, device; bus = \"Bus 2\", active = 0.4)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.1)\n\nAdding wattmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@wattmeter(label = \"Wattmeter ?\", varianceBus = 1e-1, varianceFrom = 1e-2)\naddWattmeter!(system, device; bus = \"Bus 2\", active = 40.0)\naddWattmeter!(system, device; from = \"Branch 1\", active = 10.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#Varmeter-2","page":"Measurement Model","title":"Varmeter","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(::PowerSystem, ::Measurement)\naddVarmeter!(::PowerSystem, ::Measurement, ::AC)\nupdateVarmeter!\nstatusVarmeter!\n@varmeter","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addVarmeter!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addVarmeter!","text":"addVarmeter!(system::PowerSystem, device::Measurement; label, bus, from, to, reactive,\n variance, noise, status)\n\nThe function adds a new varmeter that measures reactive power injection or reactive power flow to the Measurement type within a given PowerSystem type. The varmeter can be added to an already defined bus or branch.\n\nKeywords\n\nThe varmeter is defined with the following keywords:\n\nlabel: Unique label for the varmeter.\nbus: Label of the bus if the varmeter is located at the bus.\nfrom: Label of the branch if the varmeter is located at the from-bus end.\nto: Label of the branch if the varmeter is located at the to-bus end.\nreactive (pu or VAr): Reactive power value.\nvariance (pu or VAr): Variance of the reactive power measurement.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the reactive,\nnoise = false: uses the reactive value only.\nstatus: Operating status of the varmeter:\nstatus = 1: in-service,\nstatus = 0: out-of-service.\n\nUpdates\n\nThe function updates the varmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: variance = 1e-2, noise = false, and status = 1, which apply to varmeters located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for varmeters positioned at the buses, from-bus ends, or to-bus ends of branches using the @varmeter macro.\n\nUnits\n\nThe default units for the reactive and variance keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExamples\n\nAdding varmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 2\", reactive = 0.4)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 0.1)\n\nAdding varmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 2\", reactive = 40.0)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 10.0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addVarmeter!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addVarmeter!","text":"addVarmeter!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceBus, statusBus, varianceFrom, statusFrom, varianceTo, statusTo, noise)\n\nThe function incorporates varmeters into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact reactive power injections at buses and reactive power flows in branches defined in the AC type.\n\nKeywords\n\nvarianceBus (pu or VAr): Measurement variance for varmeters at the buses.\nstatusBus: Operating status of the varmeters at the buses:\nstatusBus = 1: in-service,\nstatusBus = 0: out-of-service.\nvarianceFrom (pu or VAr): Measurement variance for varmeters at the from-bus ends.\nstatusFrom: Operating status of the varmeters at the from-bus ends:\nstatusFrom = 1: in-service,\nstatusFrom = 0: out-of-service.\nvarianceTo (pu or VAr): Measurement variance for varmeters at the to-bus ends.\nstatusTo: Operating status of the varmeters at the to-bus ends:\nstatusTo = 1: in-service,\nstatusTo = 0: out-of-service.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the reactive powers,\nnoise = false: uses the exact reactive power values.\n\nUpdates\n\nThe function updates the varmeter field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for keywords are as follows: varianceBus = 1e-2, statusBus = 1, varianceFrom = 1e-2, statusFrom = 1, varianceTo = 1e-2, statusTo = 1, and noise = false. Users can change these default settings using the @varmeter macro.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to use volt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n@varmeter(label = \"Varmeter ?\")\naddVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updateVarmeter!","page":"Measurement Model","title":"JuliaGrid.updateVarmeter!","text":"updateVarmeter!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a varmeter.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific varmeter, provide the necessary kwargs input arguments in accordance with the keywords specified in the addVarmeter! function, along with their respective values. Ensure that the label keyword matches the label of the existing varmeter you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the varmeter field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addVarmeter! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddVarmeter!(system, device; label = \"Varmeter 1\", from = \"Branch 1\", reactive = 1.1)\nupdateVarmeter!(system, device; label = \"Varmeter 1\", reactive = 1.2, variance = 1e-4)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusVarmeter!","page":"Measurement Model","title":"JuliaGrid.statusVarmeter!","text":"statusVarmeter!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of varmeters, assigning varmeters randomly to either in-service or out-of-service states based on specified keywords.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service varmeters or allows fine-tuning:\ninserviceBus: sets only varmeters loacted at the bus,\ninserviceFrom: sets only varmeters loacted at the from-bus end,\ninserviceTo: sets only varmeters loacted at the to-bus end.\noutservice: Sets the number of out-of-service varmeters or allows fine-tuning:\noutserviceBus: sets only varmeters loacted at the bus,\noutserviceFrom: sets only varmeters loacted at the from-bus end,\noutserviceTo: sets only varmeters loacted at the to-bus end.\nredundancy: Determines in-service varmeters based on redundancy or allows fine-tuning:\nredundancyBus: determines only varmeters loacted at the bus,\nredundancyFrom: determines only varmeters loacted at the from-bus end,\nredundancyTo: determines only varmeters loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status field within the Varmeter type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\naddVarmeter!(system, device, analysis)\nstatusVarmeter!(system, device; inserviceFrom = 20)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@varmeter","page":"Measurement Model","title":"JuliaGrid.@varmeter","text":"@varmeter(label, varinaceBus, varianceFrom, varianceTo, statusBus, statusFrom, statusTo,\n noise)\n\nThe macro generates a template for a varmeter, which can be utilized to define a varmeter using the addVarmeter! function.\n\nKeywords\n\nTo establish the varmeter template, users can set default variance and status values for varmeters at buses using varianceBus and statusBus, and at both the from-bus and to-bus ends of branches using varianceFrom and statusFrom for the former and varianceTo and statusTo for the latter. Users can also configure label patterns with the label keyword, as well as specify the noise type.\n\nUnits\n\nThe default units for the varianceBus, varianceFrom, and varianceTo keywords are per-units (pu). However, users can choose to usevolt-amperes reactive (VAr) as the units by applying the @power macro.\n\nExamples\n\nAdding varmeters using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@varmeter(label = \"Varmeter ?\", varianceBus = 1e-3, varianceFrom = 1e-4)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = 0.4)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.1)\n\nAdding varmeters using a custom unit system:\n\n@power(MW, pu, pu)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@varmeter(label = \"Varmeter ?\", varianceBus = 1e-1, varianceFrom = 1e-2)\naddVarmeter!(system, device; bus = \"Bus 2\", reactive = 40.0)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 10.0)\n\n\n\n\n\n","category":"macro"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"api/measurementModel/#PMU-2","page":"Measurement Model","title":"PMU","text":"","category":"section"},{"location":"api/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(::PowerSystem, ::Measurement)\naddPmu!(::PowerSystem, ::Measurement, ::AC)\nupdatePmu!\nstatusPmu!\n@pmu","category":"page"},{"location":"api/measurementModel/#JuliaGrid.addPmu!-Tuple{PowerSystem, Measurement}","page":"Measurement Model","title":"JuliaGrid.addPmu!","text":"addPmu!(system::PowerSystem, device::Measurement; label, bus, from, to, magnitude,\n varianceMagnitude, statusMagnitude, angle, varianceAngle, statusAngle,\n noise, correlated, polar)\n\nThe function adds a new PMU to the Measurement type within a given PowerSystem type. The PMU can be added to an already defined bus or branch. When defining the PMU, it is essential to provide the bus voltage magnitude and angle if the PMU is located at a bus or the branch current magnitude and angle if the PMU is located at a branch.\n\nKeywords\n\nThe PMU is defined with the following keywords:\n\nlabel: Unique label for the PMU.\nbus: Label of the bus if the PMU is located at the bus.\nfrom: Label of the branch if the PMU is located at the from-bus end.\nto: Label of the branch if the PMU is located at the to-bus end.\nmagnitude (pu or V, A): Bus voltage or branch current magnitude value.\nvarianceMagnitude (pu or V, A): Magnitude measurement variance.\nstatusMagnitude: Operating status of the magnitude measurement:\nstatusMagnitude = 1: in-service,\nstatusMagnitude = 0: out-of-service.\nangle (rad or deg): Bus voltage or branch current angle value.\nvarianceAngle (rad or deg): Angle measurement variance.\nstatusAngle: Operating status of the angle measurement:\nstatusAngle = 1: in-service,\nstatusAngle = 0: out-of-service.\nnoise: Specifies how to generate the measurement means:\nnoise = true: adds white Gaussian noises with variances to the magnitude and angle,\nnoise = false: uses the magnitude and angle values only.\ncorrelated: Specifies error correlation for PMUs for algorithms utilizing rectangular coordinates:\ncorrelated = true: considers correlated errors,\ncorrelated = false: disregards correlations between errors.\npolar: Chooses the coordinate system for including phasor measurements in AC state estimation:\npolar = true: adopts the polar coordinate system,\npolar = false: adopts the rectangular coordinate system.\n\nUpdates\n\nThe function updates the pmu field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for certain keywords are as follows: varianceMagnitude = 1e-5, statusMagnitude = 1, varianceAngle = 1e-5, statusAngle = 1, noise = false, correlated = false, and polar = false, which apply to PMUs located at the bus, as well as at both the from-bus and to-bus ends. Users can fine-tune these settings by explicitly specifying the variance and status for PMUs positioned at the buses, from-bus ends, or to-bus ends of branches using the @pmu macro.\n\nUnits\n\nThe default units for the magnitude, varianceMagnitude, and angle, varianceAngle keywords are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) when the PMU is located at a bus using the @voltage macro, or amperes (A) and degrees (deg) when the PMU is located at a branch through the use of the @current macro.\n\nExamples\n\nAdding PMUs using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 131.8e3)\naddBus!(system; label = \"Bus 2\", base = 131.8e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 1.1, angle = 0.1)\n\nAdding PMUs using a custom unit system:\n\n@voltage(kV, deg, kV)\n@current(A, deg)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 131.8)\naddBus!(system; label = \"Bus 2\", base = 131.8)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 145, angle = -5.7)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 481, angle = 5.7)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.addPmu!-Tuple{PowerSystem, Measurement, AC}","page":"Measurement Model","title":"JuliaGrid.addPmu!","text":"addPmu!(system::PowerSystem, device::Measurement, analysis::AC;\n varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,\n varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,\n varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo,\n correlated, polar, noise)\n\nThe function incorporates PMUs into the Measurement composite type for every bus and branch within the PowerSystem type. These measurements are derived from the exact bus voltage magnitudes and angles, as well as branch current magnitudes and angles defined in the AC type.\n\nKeywords\n\nUsers have the option to configure the following keywords:\n\nvarianceMagnitudeBus (pu or V): Variance of magnitude measurements at buses.\nstatusMagnitudeBus: Operating status of magnitude measurements at buses:\nstatusMagnitudeBus = 1: in-service,\nstatusMagnitudeBus = 0: out-of-service.\nvarianceAngleBus (rad or deg): Variance of angle measurements at buses.\nstatusAngleBus: Operating status of angle measurements at buses:\nstatusAngleBus = 1: in-service,\nstatusAngleBus = 0: out-of-service.\nvarianceMagnitudeFrom (pu or A): Variance of magnitude measurements at the from-bus ends.\nstatusMagnitudeFrom: Operating status of magnitude measurements at the from-bus ends:\nstatusMagnitudeFrom = 1: in-service,\nstatusMagnitudeFrom = 0: out-of-service.\nvarianceAngleFrom (rad or deg): Variance of angle measurements at the from-bus ends.\nstatusAngleFrom: Operating status of angle measurements at the from-bus ends:\nstatusAngleFrom = 1: in-service,\nstatusAngleFrom = 0: out-of-service.\nvarianceMagnitudeTo (pu or A): Variance of magnitude measurements at the to-bus ends.\nstatusMagnitudeTo: Operating status of magnitude measurements at the to-bus ends:\nstatusMagnitudeTo = 1: in-service,\nstatusMagnitudeTo = 0: out-of-service.\nvarianceAngleTo (rad or deg): Variance of angle measurements at the to-bus ends.\nstatusAngleTo: Operating status of angle measurements at the to-bus ends:\nstatusAngleTo = 1: in-service,\nstatusAngleTo = 0: out-of-service.\ncorrelated: Specifies error correlation for PMUs for algorithms utilizing rectangular coordinates:\ncorrelated = true: considers correlated errors,\ncorrelated = false: disregards correlations between errors.\npolar: Chooses the coordinate system for including phasor measurements in AC state estimation:\npolar = true: adopts the polar coordinate system,\npolar = false: adopts the rectangular coordinate system.\nnoise: Specifies how to generate the measurement mean:\nnoise = true: adds white Gaussian noise with the variance to the magnitudes and angles,\nnoise = false: uses the exact magnitude and angles values.\n\nUpdates\n\nThe function updates the pmu field of the Measurement composite type.\n\nDefault Settings\n\nDefault settings for variance keywords are established at 1e-5, with all statuses set to 1, polar = false, correlated = false, and noise = false. Users can change these default settings using the @pmu macro.\n\nUnits\n\nThe default units for the variance keywords are in per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) when the PMU is located at a bus using the @voltage macro, or amperes (A) and degrees (deg) when the PMU is located at a branch through the use of the @current macro.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)\n\n\n\n\n\n","category":"method"},{"location":"api/measurementModel/#JuliaGrid.updatePmu!","page":"Measurement Model","title":"JuliaGrid.updatePmu!","text":"updatePmu!(system::PowerSystem, device::Measurement, [analysis::Analysis];\n kwargs...)\n\nThe function allows for the alteration of parameters for a PMU.\n\nArguments\n\nIf the Analysis type is omitted, the function applies changes to the Measurement composite type only. However, when including the Analysis type, it updates both the Measurement and Analysis types. This streamlined process avoids the need to completely rebuild vectors and matrices when adjusting these parameters.\n\nKeywords\n\nTo update a specific PMU, provide the necessary kwargs input arguments in accordance with the keywords specified in the addPmu! function, along with their respective values. Ensure that the label keyword matches the label of the existing PMU you want to modify. If any keywords are omitted, their corresponding values will remain unchanged.\n\nUpdates\n\nThe function updates the pmu field within the Measurement composite type. Furthermore, it guarantees that any modifications to the parameters are transmitted to the Analysis type.\n\nUnits\n\nUnits for input parameters can be changed using the same method as described for the addPmu! function.\n\nExample\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\n\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\nupdatePmu!(system, device; label = \"PMU 1\", magnitude = 1.05)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.statusPmu!","page":"Measurement Model","title":"JuliaGrid.statusPmu!","text":"statusPmu!(system::PowerSystem, device::Measurement; inservice, inserviceBus,\n inserviceFrom, inserviceTo, outservice, outserviceBus outserviceFrom, outserviceTo,\n redundancy, redundancyBus, redundancyFrom, redundancyTo)\n\nThe function generates a set of PMUs, assigning PMUs randomly to either in-service or out-of-service states based on specified keywords. It is important to note that when we refer to PMU, we encompass both magnitude and angle measurements.\n\nKeywords\n\nUsers may use either one main keyword or three fine-tuning keywords that specify distinct locations per function call:\n\ninservice: Sets the number of in-service PMUs or allows fine-tuning:\ninserviceBus: sets only PMUs loacted at the bus,\ninserviceFrom: sets only PMUs loacted at the from-bus end,\ninserviceTo: sets only PMUs loacted at the to-bus end.\noutservice: Sets the number of out-of-service PMUs or allows fine-tuning:\noutserviceBus: sets only PMUs loacted at the bus,\noutserviceFrom: sets only PMUs loacted at the from-bus end,\noutserviceTo: sets only PMUs loacted at the to-bus end.\nredundancy: Determines in-service PMUs based on redundancy or allows fine-tuning:\nredundancyBus: determines only PMUs loacted at the bus,\nredundancyFrom: determines only PMUs loacted at the from-bus end,\nredundancyTo: determines only PMUs loacted at the to-bus end.\n\nUpdates\n\nThe function updates the status fields within the PMU type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nacModel!(system)\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\ncurrent!(system, analysis)\n\naddPmu!(system, device, analysis)\nstatusPmu!(system, device; inserviceBus = 14)\n\n\n\n\n\n","category":"function"},{"location":"api/measurementModel/#JuliaGrid.@pmu","page":"Measurement Model","title":"JuliaGrid.@pmu","text":"@pmu(label, varianceMagnitudeBus, statusMagnitudeBus, varianceAngleBus, statusAngleBus,\n varianceMagnitudeFrom, statusMagnitudeFrom, varianceAngleFrom, statusAngleFrom,\n varianceMagnitudeTo, statusMagnitudeTo, varianceAngleTo, statusAngleTo, noise,\n correlated, polar)\n\nThe macro generates a template for a PMU, which can be utilized to define a PMU using the addPmu! function.\n\nKeywords\n\nTo establish the PMU template, users have the option to set default values for magnitude and angle variances, as well as statuses for each component of the phasor. This can be done for PMUs located at the buses using the varianceMagnitudeBus, varianceAngleBus, statusMagnitudeBus, and statusAngleBus keywords.\n\nThe same configuration can be applied at both the from-bus ends of the branches using the varianceMagnitudeFrom, varianceAngleFrom, statusMagnitudeFrom, and statusAngleFrom keywords.\n\nFor PMUs located at the to-bus ends of the branches, users can use the varianceMagnitudeTo, varianceAngleTo, statusMagnitudeTo, and statusAngleTo keywords.\n\nAdditionally, users can configure the pattern for labels using the label keyword, specify the type of noise, and indicate the correlated and polar system utilized for managing phasors during state estimation.\n\nUnits\n\nBy default, the units for variances are per-units (pu) and radians (rad). However, users have the option to switch to volts (V) and degrees (deg) as the units for PMUs located at the buses by using the @voltage macro, or they can switch to amperes (A) and degrees (deg) as the units for PMUs located at the branches by using the @current macro.\n\nExamples\n\nAdding PMUs using the default unit system:\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132e3)\naddBus!(system; label = \"Bus 2\", base = 132e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@pmu(label = \"PMU ?\", varianceAngleBus = 1e-6, varianceMagnitudeFrom = 1e-4)\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 1.1, angle = -0.2)\n\nAdding PMUs using a custom unit system:\n\n@voltage(kV, deg, kV)\n@current(A, deg)\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 132.0)\naddBus!(system; label = \"Bus 2\", base = 132.0)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.2)\n\n@pmu(label = \"PMU ?\", varianceAngleBus = 5.73e-5, varianceMagnitudeFrom = 0.0481)\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 145.2, angle = -5.73)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 481.125, angle = -11.46)\n\n\n\n\n\n","category":"macro"},{"location":"manual/dcStateEstimation/#DCStateEstimationManual","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To perform the DC state estimation, we first need to have the PowerSystem type that has been created with the DC model, alongside the Measurement type that retains measurement data. Subsequently, we can formulate either the weighted least-squares (WLS) or the least absolute value (LAV) DC state estimation model encapsulated within the type DCStateEstimation using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"dcStateEstimation,\ndcLavStateEstimation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For resolving the DC state estimation problem and obtaining bus voltage angles, utilize the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After executing the function solve!, where the user employs the WLS method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Moreover, before creating the DCStateEstimation type, users can initiate observability analysis to identify observable islands and restore observability by employing:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"islandTopologicalFlow,\nislandTopological,\nrestorationGram!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For more detailed information, users can refer to the Observability Analysis section within AC state estimation documentation. It is worth noting that when the system becomes observable within the AC model, it will also be observable within the DC state estimation model.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution for DC state estimation, JuliaGrid offers a post-processing analysis function to compute active powers associated with buses and branches:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses or branches.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCSEBusTypeModificationManual","page":"DC State Estimation","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Just like in the Bus Type Modification section, when establishing the DCStateEstimation type, the initially assigned slack bus is evaluated and may be altered. If the designated slack bus (type = 3) lacks a connected in-service generator, it will be changed to a demand bus (type = 1). Conversely, the first generator bus (type = 2) with an active in-service generator linked to it will be reassigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCWLSStateEstimationSolutionManual","page":"DC State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To solve the DC state estimation and derive WLS estimates using JuliaGrid, the process initiates by defining PowerSystem and Measurement types. Here is an illustrative example:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.2)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.4)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.2)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 3\", active = -0.4, variance = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.18, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 2\", active = -0.42, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The dcStateEstimation function serves to establish the DC state estimation problem:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the DC state estimation problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = dcStateEstimation(system, device, LDLt)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain the bus voltage angles, the solve! function can be invoked as shown:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Upon obtaining the solution, access the bus voltage angles using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe recommend that readers refer to the tutorial on DC State Estimation for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Alternative-Formulation","page":"DC State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Specifically, by specifying the Orthogonal argument in the dcStateEstimation function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis = dcStateEstimation(system, device, Orthogonal)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Print-Results-in-the-REPL","page":"DC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Save-Results-to-a-File","page":"DC State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nWe also provide functions to print state estimation results, such as estimated values and residuals. For more details, users can consult the Power Analysis section of this manual.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCBadDataDetectionManual","page":"DC State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After acquiring the WLS solution using the solve! function, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new wattmeter. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"addWattmeter!(system, device; from = \"Branch 2\", active = 4.1, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the DC state estimation model:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective measurements as out-of-service within the Measurement type.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Moreover, JuliaGrid will adjust the coefficient matrix and mean vector within the DCStateEstimation type based on measurements now designated as out-of-service. To optimize the algorithm's efficiency, JuliaGrid resets non-zero elements to zero in the coefficient matrix and mean vector, effectively removing the impact of the corresponding measurement on the solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"analysis.method.mean\nanalysis.method.coefficient","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Hence, after removing bad data, a new estimate can be computed without considering this specific measurement:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCLAVtateEstimationSolutionManual","page":"DC State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Setup-Starting-Primal-Values","page":"DC State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the DCStateEstimation type. By default, these values are initially established using the initial bus voltage angles from PowerSystem type:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Solution","page":"DC State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Upon obtaining the solution, access the bus voltage angles using:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCMeasurementsAlterationManual","page":"DC State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the DCStateEstimation type using the dcStateEstimation or dcLavStateEstimation function. Ultimately, resolving the DC state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.1)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.11, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.09, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for the model\nsolve!(system, analysis)\n\naddWattmeter!(system, device; to = \"Branch 1\", active = -0.12, variance = 1e-4)\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", status = 0)\nupdateWattmeter!(system, device; label = \"Wattmeter 2\", active = 0.1, noise = false)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for new model\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCStateEstimationUpdateManual","page":"DC State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"An advanced methodology involves users establishing the DCStateEstimation type using dcStateEstimation or dcLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the DCStateEstimation type.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where DCStateEstimation also does not need to be recreated. Such efficiency can be particularly advantageous in cases where JuliaGrid can reuse gain matrix factorization.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of DCStateEstimation is not practical in terms of reusing this type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can modify the prior example to achieve the same model without establishing DCStateEstimation twice:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.1)\n\n@wattmeter(label = \"Wattmeter ?\")\naddWattmeter!(system, device; bus = \"Bus 2\", active = -0.11, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.09, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 1\", active = -0.12, variance = 1e-4, status = 0)\n\nanalysis = dcStateEstimation(system, device) # <- Build DCStateEstimation for the model\nsolve!(system, analysis)\n\nupdateWattmeter!(system, device; label = \"Wattmeter 1\", status = 0)\nupdateWattmeter!(system, device; label = \"Wattmeter 2\", active = 0.1, noise = false)\nupdateWattmeter!(system, device; label = \"Wattmeter 3\", status = 1)\n\n# <- No need for re-build; we have already updated the existing DCStateEstimation instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the DCStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Reusing-Weighted-Least-Squares-Matrix-Factorization","page":"DC State Estimation","title":"Reusing Weighted Least-Squares Matrix Factorization","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Drawing from the preceding example, our focus now shifts to finding a solution involving modifications that entail adjusting the measurement value of the Wattmeter 2. It is important to note that these adjustments do not impact the variance or status of the measurement device, which can affect the gain matrix. To resolve this updated system, users can simply execute the solve! function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nupdateWattmeter!(system, device, analysis; label = \"Wattmeter 2\", active = 0.091)\n\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nIn this scenario, JuliaGrid will recognize instances where the user has not modified parameters that impact the gain matrix. Consequently, JuliaGrid will leverage the previously performed gain matrix factorization, resulting in a significantly faster solution compared to recomputing the factorization.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#DCSEPowerAnalysisManual","page":"DC State Estimation","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"After obtaining the solution from the DC state estimation, calculating powers related to buses and branches is facilitated by using the power! function. For instance, let us consider the model for which we obtained the DC state estimation solution:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, conductance = 1e-3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.2)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.4)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.2)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.3)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; bus = \"Bus 3\", active = -0.4, variance = 1e-2)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.18, variance = 1e-4)\naddWattmeter!(system, device; to = \"Branch 2\", active = -0.42, variance = 1e-4)\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"We can compute active powers using the following function:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For example, active power injections corresponding to buses are:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"print(system.bus.label, analysis.power.injection.active)","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"note: Info\nTo better understand the powers associated with buses, and branches that are calculated by the power! function, we suggest referring to the tutorials on.","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Print-Results-in-the-REPL-2","page":"DC State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Users can utilize any of the print functions outlined in the Print API related to the DC analysis. For example, to print state estimation data related to wattmeters, we can use:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"@power(MW, pu, pu)\nprintWattmeterData(system, device, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Save-Results-to-a-CSV-File","page":"DC State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintWattmeterData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Injection","page":"DC State Estimation","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Injection-from-Generators","page":"DC State Estimation","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"","category":"page"},{"location":"manual/dcStateEstimation/#Active-Power-Flow","page":"DC State Estimation","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcStateEstimation/","page":"DC State Estimation","title":"DC State Estimation","text":"active = fromPower(system, analysis; label = \"Branch 1\")\nactive = toPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"tutorials/acPowerFlow/#ACPowerFlowTutorials","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid uses standard network components and the Unified Branch Model for power flow analysis, allowing load profiles, generator capacities, voltage specifications, contingency analysis, and planning to be defined efficiently.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integer)\n\n@power(MW, MVAr, MVA)\n@voltage(pu, deg, V)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3)\naddBus!(system; label = 2, type = 1, active = 21.7, reactive = 12.7)\naddBus!(system; label = 3, type = 1, active = 11.2, reactive = -3.0)\naddBus!(system; label = 4, type = 2, conductance = 2.1, susceptance = 1.2)\n\naddBranch!(system; from = 1, to = 2, resistance = 0.02, reactance = 0.06)\naddBranch!(system; from = 1, to = 3, resistance = 0.05, reactance = 0.21)\naddBranch!(system; from = 2, to = 3, resistance = 0.13, reactance = 0.26)\naddBranch!(system; from = 3, to = 4, reactance = 0.17, susceptance = 0.2, conductance = 1e-4)\n\naddGenerator!(system; bus = 1)\naddGenerator!(system; bus = 3, active = 40.0, reactive = 42.4)\nnothing #hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = hcat([𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]])","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element associated with bus i in mathcalN, and a_ij represents the element associated with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#FlowNodalNetworkEquationsTutorials","page":"AC Power Flow","title":"Nodal Network Equations","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As previously demonstrated in the section on the Nodal Network Equations, we observe the system of equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfbar I = mathbfY mathbfbar V","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The complex current injection at the bus i in mathcalN is defined as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barI_i = cfracS_i^*barV_i^*","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, for any given bus i in mathcalN, we can express it as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" cfracS_i^*barV_i^* = sum_j = 1^n Y_ij bar V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The complex power injection denoted by S_i consists of both the active power P_i and reactive power Q_i. This relationship can be represented as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" cfracP_i - textjQ_ibarV_i = sum_j = 1^n Y_ij bar V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Recognizing that Y_ij = G_ij + textjB_ij, barV_i = V_i texte^textjtheta_i, barV_j = V_j texte^textjtheta_j, and by defining theta_ij = theta_i - theta_j, we can break down the above equation into its real and imaginary parts, resulting in two equations that describe bus i in mathcalN as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n P_i =V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j\n Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As demonstrated by the above equations, the bus i in mathcalN contains four unknown variables: the active power injection P_i, reactive power injection Q_i, bus voltage magnitude V_i, and bus voltage angle theta_i.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To solve these equations, it is necessary to specify two known variables. Although any two variables can be selected mathematically, the choice is determined by the devices that are connected to a particular bus. The standard options are listed in the table below, and these options are used to define the bus types [9].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Type Label Known Unknown\nDemand 1 P_i, Q_i V_i, theta_i\nGenerator 2 P_i, V_i Q_i, theta_i\nSlack 3 V_i, theta_i P_i, Q_i","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Consequently, JuliaGrid operates with sets mathcalN_textpq and mathcalN_textpv that contain demand and generator buses, respectively, and exactly one slack bus in the set mathcalN_textsb. The bus types are stored in the variable:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"system.bus.layout.type","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"It should be noted that JuliaGrid cannot handle systems with multiple slack buses. Additionally, when using functions such as newtonRaphson, fastNewtonRaphsonBX, fastNewtonRaphsonXB, and gaussSeidel, the bus type can be modified as discussed in the section on Bus Type Modification.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Furthermore, active power injections P_i and reactive power injections Q_i can be expressed as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n \tP_i = P_textpi - P_textdi \n Q_i = Q_textpi - Q_textdi\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textdi and Q_textdi denote the active and reactive power demanded at the bus i in mathcalN, while P_textpi and Q_textpi correspond to the active and reactive power produced by the generators at the bus i in mathcalN.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To provide a more comprehensive understanding, it is important to note that each bus i in mathcalN has the capacity to host multiple generators. This scenario can be conceptualized by introducing the set mathcalS_i, which encompasses all generators connected to bus i in mathcalN. With this perspective, we can calculate the values of P_textpi and Q_textpi as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n \tP_textpi = sum_k in mathcalS_i P_textgk\n Q_textpi = sum_k in mathcalS_i Q_textgk\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textgk and Q_textgk represent the active and reactive power outputs of the k-th generator within the set mathcalS_i.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As a way to summarize, the power injection vectors, represented as mathbfP = P_i and mathbfQ = Q_i can be computed based on the following variables and expressions:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏 = system.bus.supply.active - system.bus.demand.active\n𝐐 = system.bus.supply.reactive - system.bus.demand.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Positive active or reactive power values, P_i 0 or Q_i 0, signify that power is being supplied into the power system from the specific bus. This indicates that the generators connected to this bus are producing more power than what the connected load is consuming. Conversely, negative values, P_i 0 or Q_i 0, indicate that the bus is drawing in active or reactive power from the power system. This suggests that the load's demand is exceeding the output from the generators.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#NewtonRaphsonMethodTutorials","page":"AC Power Flow","title":"Newton-Raphson Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Newton-Raphson method is commonly used in AC power flow calculations due to its quadratic rate of convergence. It provides an accurate approximation of the roots of the system of nonlinear equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbff(mathbfx) = mathbf0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This, in turn, allows for the determination of unknown voltage magnitudes and angles of buses, represented by the state vector mathbf x = mathbf x_texta mathbf x_textm^T. The state vector comprises two components:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"mathbf x_texta in mathbbR^n-1, which holds the bus voltage angles of demand and generator buses, represented by mathbf x_texta = theta_i, where i in mathcalN_textpq cup mathcalN_textpv,\nmathbf x_textm in mathbbR^n_textpq, which holds the bus voltage magnitudes of demand buses, represented by mathbf x_textm = V_i, where i in mathcalN_textpq, and n_textpq = mathcalN_textpq.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Knowing the voltage magnitudes and angles for certain types of buses is a consequence of the structure of the state vector mathbf x. Specifically, the voltage magnitude and angle at the slack bus are known, as well as the voltage magnitude at generator buses.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As detailed in the Nodal Network Equations section of this manual, the expressions for active and reactive power injection are as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n P_i =V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j\n Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Using the above equations, we can define the active power injection function for demand and generator buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - P_i = 0\n forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"and the reactive power injection function for demand buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - Q_i = 0\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The active and reactive mismatches, often denoted as Delta P_i(mathbf x) and Delta Q_i(mathbf x), respectively, are defined as the functions f_P_i(mathbf x) and f_Q_i(mathbf x). The first terms on the right-hand side represent power injections at a bus, while the second term is constant and is obtained based on the active and reactive powers of the generators that supply a bus and active and reactive powers demanded by consumers at the same bus. Therefore, the Newton-Raphson method solves the system of nonlinear equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbff(x) =\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where the first n - 1 equations correspond to demand and generator buses, and the last n_textpq equations correspond to demand buses.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To compute the voltage magnitudes and angles of buses using the Newton-Raphson method in JuliaGrid, you must first execute the acModel! function to set up the system, followed by initializing the Newton-Raphson method using the newtonRaphson function. The following code snippet demonstrates this process:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = newtonRaphson(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This results in the creation of the starting vectors of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0), as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Here, we utilize a \"flat start\" approach in our method. It is important to keep in mind that when dealing with initial conditions in this manner, the Newton-Raphson method may encounter difficulties.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To implement the Newton-Raphson method, the iterative approach based on the Taylor series expansion, JuliaGrid provides the mismatch! and solve! functions. These functions are utilized to carry out the Newton-Raphson method iteratively until a stopping criterion is reached, as demonstrated in the following code snippet:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The mismatch! function calculates the mismatch in active power injection for demand and generator buses and the mismatch in reactive power injection for demand buses at each iteration nu = 1 2 dots. The equations used for these computations are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x^(nu-1)) = V_i^(nu-1)sumlimits_j=1^n (G_ijcostheta_ij^(nu-1)+B_ijsintheta_ij^(nu-1))V_j^(nu-1) - P_i\n forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"as well as the reactive power injection mismatch for demand buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x^(nu-1)) = V_i^(nu)sumlimits_j=1^n (G_ijsintheta_ij^(nu-1)-B_ijcostheta_ij^(nu-1))V_j^(nu-1) - Q_i\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting vector from these calculations is stored in the mismatch variable of the ACPowerFlow abstract type and can be accessed through the following line of code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐟 = analysis.method.mismatch","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In addition to computing the mismatches in active and reactive power injection, the mismatch! function also returns the maximum absolute values of these mismatches. These maximum values are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max f_P_i(mathbf x^(nu-1)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max f_Q_i(mathbf x^(nu-1)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the function solve! computes the increments of bus voltage angle and magnitude at each iteration using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfDelta mathbfx^(nu-1) = -mathbfJ(mathbfx^(nu-1))^-1 mathbff(mathbfx^(nu-1))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where mathbfDelta mathbfx = mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm^T consists of the vector of bus voltage angle increments mathbf Delta mathbf x_texta in mathbbR^n-1 and bus voltage magnitude increments mathbf Delta mathbf x_textm in mathbbR^n_textpq, and mathbfJ(mathbfx) in mathbbR^n_textu times n_textu is the Jacobian matrix, n_textu = n + n_textpq - 1.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing the Jacobian matrix mathbfJ = mathbfLmathbfU, aiming to compute the increments. Nevertheless, users have the flexibility to opt for QR factorization as an alternative method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These values are stored in the ACPowerFlow abstract type and can be accessed after each iteration:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱 = analysis.method.increment\n𝐉 = analysis.method.jacobian\n𝐋 = analysis.method.factorization.L\n𝐔 = analysis.method.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The JuliaGrid implementation of the AC power flow follows a specific order to store the increment mathbfDelta mathbfx and mismatch mathbff(x) vectors. The first n-1 elements of both vectors correspond to the demand and generator buses in the same order as they appear in the input data. The first n-1 elements of the increment vector mathbfDelta mathbfx correspond to the voltage angle increments mathbf Delta mathbf x_texta, while the first n-1 elements of the mismatch vector mathbff(x) correspond to the mismatch in active power injections mathbff_textP(mathbf x).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The last n_textpq elements of the increment mathbfDelta mathbfx and mismatch mathbff(x) vectors correspond to the demand buses in the order they appear in the input data. For the increment vector mathbfDelta mathbfx, it matches the bus voltage magnitude increments mathbf Delta mathbf x_textm, while for the mismatch vector mathbff(x), it matches the mismatch in reactive power injections mathbff_textQ(mathbf x).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"These specified orders dictate the row and column order of the Jacobian matrix mathbfJ(mathbfx).","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Finally, the function solve! adds the computed increment term to the previous solution to obtain a new solution:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x^(nu) = mathbf x^(nu-1) + mathbf Delta mathbf x^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The bus voltage magnitudes mathbfV = V_i and angles bmTheta = theta_i are then updated based on the obtained solution mathbf x. It is important to note that only the voltage magnitudes related to demand buses and angles related to demand and generator buses are updated; not all values are updated. Therefore, the final solution obtained by JuliaGrid is stored in the following vectors:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Jacobian-Matrix","page":"AC Power Flow","title":"Jacobian Matrix","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To complete the tutorial on the Newton-Raphson method, we will now describe the Jacobian matrix and provide the equations involved in its evolution. Without loss of generality, we assume that the slack bus is the first bus, followed by the set of demand buses and the set of generator buses:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathcalN_textsb = 1 \n mathcalN_textpq = 2 dots m \n mathcalN_textpv = m + 1dots n\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where mathcalN = mathcalN_textsb cup mathcalN_textpq cup mathcalN_textpv. Therefore, we can express:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbf x_texta = theta_2dotstheta_n^T mathbf Delta mathbf x_texta = Delta theta_2dotsDelta theta_n^T \n mathbf x_textm = V_2dotsV_m^T mathbf Delta mathbf x_textm = Delta V_2dotsDelta V_m^T\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Jacobian matrix mathbfJ(x^(nu)) in mathbbR^n_textu times n_textu is:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbfJ(x^(nu))=\n left\n beginarraycccccc\n cfracmathrm partialf_P_2(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_P_2(mathbf x^(nu))mathrm partial V_m\n vdots \n cfracmathrm partialf_P_n(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_P_n(mathbf x^(nu))mathrm partial V_m 10pt\n hline \n cfracmathrm partialf_Q_2(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_Q_2(mathbf x^(nu))mathrm partial V_m\n vdots \n cfracmathrm partialf_Q_m(mathbf x^(nu)) mathrm partial theta_2 cdots \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial theta_n \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial V_2 cdots \n cfracmathrm partialf_Q_m(mathbf x^(nu))mathrm partial V_m\n endarray\n right","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Jacobian matrix can be expressed using four block matrices:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"\tmathbfJ(x^(nu)) =\n beginbmatrix\n mathbfJ_11(x^(nu)) mathbfJ_12(x^(nu)) mathbfJ_21(x^(nu)) \n\t mathbfJ_22(x^(nu))\n endbmatrix","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where diagonal elements of the Jacobian sub-matrices are defined as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x^(nu)) mathrm partial theta_i =\n V_i^(nu)sumlimits_j=1^n (-G_ijsintheta_ij^(nu)+B_ijcostheta_ij^(nu))V_j^(nu) - B_ii(V_i^(nu))^2\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial V_i^(nu) =\n sumlimits_j=1^n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_j^(nu) + G_iiV_i^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu)) mathrm partial theta_i =\n V_i^(nu) sumlimits_j=1^n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_j^(nu) - G_ii(V_i^(nu))^2\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrm partial V_i =\n sumlimits_j=1^n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_j^(nu) - B_iiV_i^(nu)\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"while non-diagonal elements of the Jacobian sub-matrices are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial theta_j =\n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_i^(nu)V_j^(nu)\n cfracmathrm partialf_P_i(mathbf x^(nu))mathrm partial V_j^(nu) =\n (G_ijcostheta_ij^(nu)+B_ijsintheta_ij^(nu))V_i^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrm partial theta_j =\n -(G_ijcostheta_ij^(nu) + B_ijsintheta_ij^(nu))V_i^(nu)V_j^(nu)\n cfracmathrm partialf_Q_i(mathbf x^(nu))mathrmpartial V_j =\n (G_ijsintheta_ij^(nu)-B_ijcostheta_ij^(nu))V_i^(nu)\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#FastNewtonRaphsonMethodTutorials","page":"AC Power Flow","title":"Fast Newton-Raphson Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Although the fast Newton-Raphson method may converge more slowly than the traditional Newton-Raphson method, the shorter solution time for the updates often compensates for this slower convergence, resulting in a shorter overall solution time. This is particularly true for systems that are not heavily loaded, where a shorter overall solution time is almost always achieved. It is important to note that if the algorithm converges, it will converge to a correct solution [6].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The fast Newton-Raphson method involves decoupling the power flow equations. Namely, the Newton-Raphson method is based on the equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginbmatrix\n mathbfJ_11(x) mathbfJ_12(x) mathbfJ_21(x) \n\t mathbfJ_22(x)\n endbmatrix\n beginbmatrix\n mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm\n endbmatrix\t+\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where the iteration index has been omitted for simplicity. However, in transmission grids, there exists a strong coupling between active powers and voltage angles, as well as between reactive powers and voltage magnitudes. To achieve decoupling, two conditions must be satisfied: first, the resistance values r_ij of the branches must be small compared to their reactance values x_ij, and second, the angle differences must be small, i.e., theta_ij approx 0 [10]. Therefore, starting from the above equation, we have:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginbmatrix\n mathbfJ_11(x) mathbf0 mathbf0 mathbfJ_22(x)\n endbmatrix\n beginbmatrix\n mathbf Delta mathbf x_texta mathbf Delta mathbf x_textm\n endbmatrix\t+\n beginbmatrix\n mathbff_textP(mathbf x) mathbff_textQ(mathbf x)\n endbmatrix = mathbf 0","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"which gives the decoupled system as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbff_textP(mathbf x) = -mathbfJ_11(x) mathbf Delta mathbf x_texta \n mathbff_textQ(mathbf x) = -mathbfJ_22(x) mathbf Delta mathbf x_textm\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To examine the problem, it is helpful to express it as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = -Delta theta_2cfracmathrm partialf_P_2(mathbf x) mathrm partial theta_2 - cdots -\n Delta theta_n cfracmathrm partialf_P_2(mathbf x)mathrm partial theta_n \n vdots \n f_P_n(mathbf x) = -Delta theta_2cfracmathrm partialf_P_n(mathbf x) mathrm partial theta_2 - cdots -\n Delta theta_n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_n\n f_Q_2(mathbf x) = - Delta V_2 cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_2 - cdots -\n Delta V_n_textpq cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_m\n vdots \n f_Q_m(mathbf x) = - Delta V_2 cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_2 - cdots -\n Delta V_m cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Firstly, the second part of the expressions is expanded as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_Q_2(mathbf x) =\n -cfracDelta V_2V_2V_2 cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_2 - cdots -\n cfracDelta V_mV_m V_m\n cfracmathrm partialf_Q_2(mathbf x)mathrm partial V_m\n vdots \n f_Q_m(mathbf x) =\n - cfracDelta V_2V_2V_2 cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_2 - cdots -\n cfracDelta V_mV_m V_m\n cfracmathrm partialf_Q_m(mathbf x)mathrm partial V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the Jacobian elements are derived. To achieve this, we can use the expressions defined for the Newton-Raphson method. For demand buses, the above expansions are applied as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i =\n V_isumlimits_j=1^n (-G_ijsintheta_ij+B_ijcostheta_ij)V_j - B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij)V_iV_j\n V_i cfracmathrm partialf_Q_i(mathbf x)mathrm partial V_i =\n V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - B_iiV_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j =\n (G_ijsintheta_ij-B_ijcostheta_ij) V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As the definition of reactive power is given by the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_i =V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"the Jacobian elements can be expressed in the following manner:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i =\n -Q_i - B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x)mathrm partial theta_j =\n (G_ijsintheta_ij-B_ijcostheta_ij) V_i V_j\n V_i cfracmathrm partialf_Q_i(mathbf x)mathrm partial V_i =\n Q_i - B_ii V_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j =\n (G_ijsintheta_ij - B_ijcostheta_ij) V_i V_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The decoupled model is established through the following approximations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n sin(theta_ij) approx 0 \n cos(theta_ij) approx 1 \n Q_i B_iiV_i^2\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, when the approximations are made, the Jacobian elements are simplified, resulting in the decoupled model where the Jacobian elements are:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_i = -B_iiV_i^2\n cfracmathrm partialf_P_i(mathbf x) mathrm partial theta_j = -B_ijV_iV_j\n V_i cfracmathrm partialf_Q_i(mathbf x) mathrm partial V_i = -B_iiV_i^2\n V_j cfracmathrm partialf_Q_i(mathbf x)mathrmpartial V_j = -B_ijV_iV_j\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Thus, the initial system of equations becomes:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = B_22 Delta theta_2 V_2^2 + cdots + B_2n Delta theta_n V_2V_n \n vdots \n f_P_n(mathbf x) = B_n2 Delta theta_2 V_2V_n + cdots + B_nn Delta theta_n V_n^2 \n f_Q_2(mathbf x) = B_22 cfracDelta V_2V_2 V_2^2 + cdots + B_2m cfracDelta V_mV_m V_2V_m \n vdots \n f_Q_m(mathbf x) = B_m2 cfracDelta V_2V_2 V_2V_m + cdots + B_mm cfracDelta V_mV_m V_m^2\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Using V_j approx 1, wherein V_i^2 = V_iV_j j=i, the first part of the equations can be simplified to:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_2(mathbf x) = B_22 Delta theta_2 V_2 + cdots + B_2n Delta theta_n V_2\n vdots \n f_P_n(mathbf x) = B_n2 Delta theta_2 V_n + cdots + B_nn Delta theta_n V_n\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, the second part of the equations can be simplified to:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_Q_2(mathbf x) = B_22 V_2 Delta V_2 + cdots + B_2m V_2 Delta V_m\n \n vdots \n f_Q_m(mathbf x) = B_m2 V_m Delta V_2 + cdots + B_mm V_m Delta V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The fast Newton-Raphson method is ultimately based on the system of equations presented below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n cfracf_P_2(mathbf x)V_2 = B_22 Delta theta_2 + cdots + B_2n Delta theta_n \n vdots \n cfracf_P_n(mathbf x)V_n = B_n2 Delta theta_2 + cdots + B_nn Delta theta_n \n cfracf_Q_2(mathbf x)V_2 = B_22 Delta V_2 + cdots + B_2m Delta V_m \n vdots \n cfracf_Q_m(mathbf x)V_m = B_m2 Delta V_2 + cdots +\n B_mm Delta V_m\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This system can be written as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n mathbfh_textP(mathbf x) = mathbfB_1 mathbf Delta mathbf x_texta \n mathbfh_textQ(mathbf x) = mathbfB_2 mathbf Delta mathbf x_textm\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"One of the main advantages of this approach is that the Jacobian matrices mathbfB_1 and mathbfB_2 are constant and need only be formed once. Furthermore, this method can be used to define both the XB and BX versions of the fast Newton-Raphson method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#XB-Version","page":"AC Power Flow","title":"XB Version","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The matrix mathbfB_1 is formed by neglecting the resistance r_ij, shunt susceptance Im y_textshi , charging susceptance Im y_textsij , and transformer tap ratio magnitude tau_ij. The matrix mathbfB_2 is constructed by disregarding the transformer phase shift angle phi_ij. This approach corresponds to the standard fast Newton-Raphson method and is known to exhibit exceptional convergence properties in typical scenarios [10].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To initialize the XB version of the fast Newton-Raphson method, one can utilize the following code snippet:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = fastNewtonRaphsonXB(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#BX-Version","page":"AC Power Flow","title":"BX Version","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The matrix mathbfB_1 ignores the shunt susceptanceIm y_textshi , charging susceptance Im y_textsij , and transformer tap ratio magnitude tau_ij. The matrix mathbfB_2 ignores the resistance r_ij and transformer phase shift angle phi_ij. In usual cases, the iteration count for the BX version is comparable to the XB scheme. However, for systems with high r_ijx_ij ratios, the BX scheme requires considerably fewer iterations than the XB scheme to solve the power flow [10].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To initialize the BX version of the fast Newton-Raphson method, you can use the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = fastNewtonRaphsonBX(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization-2","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"When a user creates the fast Newton-Raphson method in JuliaGrid, the Jacobian matrices mathbfB_1 and mathbfB_2 are formed to correspond to the active and reactive power equations, respectively:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐁₁ = analysis.method.active.jacobian\n𝐁₂ = analysis.method.reactive.jacobian","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Additionally, during this stage, JuliaGrid generates the starting vectors for bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0) as demonstrated below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process-2","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the mismatch! and solve! functions to implement the fast Newton-Raphson method iterations. These functions are used iteratively until a stopping criterion is met, as shown in the code snippet below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The functions mathbff_textP(mathbf x) and mathbff_textQ(mathbf x) remain free of approximations, with only the calculation of the state variable increments affected [6]. As a result, we still use the following equations to compute the mismatches:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n f_P_i(mathbf x) = V_isumlimits_j=1^n (G_ijcostheta_ij+B_ijsintheta_ij)V_j - P_i = 0\n forall i in mathcalN_textpq cup mathcalN_textpv\n f_Q_i(mathbf x) = V_isumlimits_j=1^n (G_ijsintheta_ij-B_ijcostheta_ij)V_j - Q_i = 0\n forall i in mathcalN_textpq\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Therefore, the mismatch! function calculates the mismatch in active power injection for demand and generator buses and the mismatch in reactive power injection for demand buses at each iteration nu = 1 2 dots:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n h_P_i(mathbf x^(nu-1)) =\n sumlimits_j=1^n (G_ijcostheta_ij^(nu-1)+B_ijsintheta_ij^(nu-1))V_j^(nu-1) - cfracP_iV_i^(nu-1)\n forall i in mathcalN_textpq cup mathcalN_textpv \n h_Q_i(mathbf x^(nu-1)) =\n sumlimits_j=1^n (G_ijsintheta_ij^(nu-1)-B_ijcostheta_ij^(nu-1))V_j^(nu-1) - cfracQ_iV_i^(nu-1)\n forall i in mathcalN_textpq\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting vectors from these calculations are stored in the ACPowerFlow abstract type and can be accessed through the following:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐡ₚ = analysis.method.active.increment\n𝐡ₒ = analysis.method.reactive.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In addition to computing the mismatches in active and reactive power injection, the mismatch! function also returns the maximum absolute values of these mismatches. These maximum values are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max h_P_i(mathbf x^(nu)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max h_Q_i(mathbf x^(nu)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Next, the function solve! computes the bus voltage angle increments:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf Delta mathbf x_texta^(nu-1) = mathbfB_1^-1 mathbfh_textP(mathbf x^(nu-1))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the voltage angle increments, JuliaGrid initially performs LU factorization on the Jacobian matrix mathbfB_1 = mathbfL_1mathbfU_1. This factorization is executed only once and is utilized in each iteration of the algorithm:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐋₁ = analysis.method.active.factorization.L\n𝐔₁ = analysis.method.active.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"tip: Tip\nBy default, JuliaGrid uses LU factorization as the primary method for factorizing Jacobian matrix. Nevertheless, users have the flexibility to opt for QR factorization as an alternative method.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vector of increments that corresponds to the active power equations can be accessed using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱ₐ = analysis.method.active.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The solution is then updated as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x_texta^(nu) = mathbf x_texta^(nu-1) + mathbf Delta mathbf x_texta^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"It is important to note that only the voltage angles related to demand and generator buses are updated, while the vector of bus voltage angles of all buses is stored:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After calculating the update for voltage angles, to calculate the magnitude updates the fast Newton-Raphson method then solves the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf Delta mathbf x_textm^(nu-1) = mathbfB_2^-1 mathbfh_textQ(mathbf x^(nu))","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly to the previous instance, JuliaGrid initially executes LU factorization on the Jacobian matrix mathbfB_2 = mathbfL_2mathbfU_2. However, it provides the flexibility for users to opt for QR factorization instead. This factorization occurs only once and is utilized in each iteration of the fast Newton-Raphson algorithm:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐋₂ = analysis.method.reactive.factorization.L\n𝐔₂ = analysis.method.reactive.factorization.U","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vector of increments that corresponds to the reactive power equations can be accessed using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝚫𝐱ₘ = analysis.method.active.increment","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Finally, the solution is updated as follows:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" mathbf x_textm^(nu) = mathbf x_textm^(nu-1) + mathbf Delta mathbf x_textm^(nu-1)","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Again, it is important to note that only the voltage magnitudes of demand buses are updated, while the vector of bus voltage magnitude for all buses is stored:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GaussSeidelMethodTutorials","page":"AC Power Flow","title":"Gauss-Seidel Method","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"As elaborated in the Nodal Network Equations section of this manual, each bus is associated with the balance equation expressed as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" sum_j = 1^n Y_ij bar V_j = cfracP_i - textjQ_ibarV_i forall i in mathcalN","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In its expanded form, this can be written as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n Y_11 barV_1 + cdots+ Y_1nbarV_n = fracP_1 - jQ_1barV_1^* \n vdots \n Y_n1 barV_1 + cdots+ Y_nnbarV_n = fracP_n - jQ_nbarV_n^*\n\tendaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"While the Gauss-Seidel method directly solves the system of equations, it suffers from very slow convergence, which increases almost linearly with the system size, necessitating numerous iterations to obtain the desired solution [11]. Moreover, the convergence time of the Gauss-Seidel method increases significantly for large-scale systems and can face convergence issues for systems with high active power transfers. Nevertheless, power flow programs utilize both the Gauss-Seidel and Newton-Raphson methods in a complementary manner. Specifically, the Gauss-Seidel method is employed to obtain a quick approximate solution from a \"flat start\", while the Newton-Raphson method is utilized to obtain the final accurate solution [8].","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The Gauss-Seidel method is usually applied to a system of n complex equations, where one represents the slack bus. Consequently, one equation can be eliminated, resulting in a power flow problem with n-1 equations.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Initialization-3","page":"AC Power Flow","title":"Initialization","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid provides a way to utilize the Gauss-Seidel method for solving the AC power flow problem and determining the magnitudes and angles of bus voltages. To use this method, we need to execute the acModel! function first to set up the system and then initialize the Gauss-Seidel method using the gaussSeidel function. The code snippet below demonstrates this process:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"acModel!(system)\nanalysis = gaussSeidel(system)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"This results in the creation of the starting vectors of bus voltage magnitudes mathbfV^(0) and angles bmTheta^(0), as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕⁽⁰⁾ = analysis.voltage.magnitude\n𝚯⁽⁰⁾ = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Iterative-Process-3","page":"AC Power Flow","title":"Iterative Process","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the mismatch! and solve! functions to implement the Gauss-Seidel method iterations. These functions are used iteratively until a stopping criterion is met, as shown in the code snippet below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"for iteration = 1:300\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In contrast to the Newton-Raphson and fast Newton-Raphson methods, the Gauss-Seidel method does not require the calculation of the mismatch in active and reactive power injection at each iteration. Instead, the mismatch! function is used solely to verify the convergence criteria. At each iteration nu = 1 2 dots, we calculate the active power injection mismatch for demand and generator buses, as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_P_i(mathbf x^(nu-1)) = RebarV_i^(nu - 1) barI_i^*(nu - 1) - P_i forall i in mathcalN_textpq cup mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"We also compute the reactive power injection mismatch for demand buses, given by:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" f_Q_i(mathbf x^(nu-1)) = ImbarV_i^(nu - 1) barI_i^*(nu - 1) - Q_i forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"However, these mismatches are not stored, as they are only used to obtain the maximum absolute values of these mismatches. The maximum values of these mismatches are used as termination criteria for the iteration loop if both are less than a predefined stopping criterion epsilon, as shown below:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" max f_P_i(mathbf x^(nu-1)) forall i in mathcalN_textpq cup mathcalN_textpv epsilon \n max f_Q_i(mathbf x^(nu-1)) forall i in mathcalN_textpq epsilon","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"After initializing complex bus voltages barV_i^(0) for all buses in the power system, the function solve! proceeds to compute the voltages for demand buses using the Gauss-Seidel method:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barV_i^(nu) =\n cfrac1Y_ii Bigg(cfracP_i - jQ_ibarV_i^*(nu-1) -\n sumlimits_substackj = 1^i - 1 Y_ijbarV_j^(nu) -\n sumlimits_substackj = i + 1^n Y_ijbarV_j^(nu-1)Bigg)\n forall i in mathcalN_textpq","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The next step is to determine the solution for generator buses in two stages: first, the reactive power injection is calculated, and then the bus complex voltage is updated using the following equations:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" beginaligned\n Q_i^(nu) =\n -Im left barV_i^*(nu) sumlimits_j=1^n Y_ijbarV_j^(nu)right forall i in mathcalN_textpv \n barV_i^(nu ) =\n cfrac1Y_ii Bigg(cfracP_i - jQ_i^(nu)barV_i^*(nu )-\n sumlimits_substackj = 1j neq i^n Y_ijbarV_j^(nu) Bigg) forall i in mathcalN_textpv\n endaligned","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The obtained voltage magnitude may not be equal to the magnitude specified for the generator bus, so a voltage correction step is necessary:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" barV_i^(nu) = V_i^(0) cfracbarV_i^(nu)V_i^(nu) forall i in mathcalN_textpv","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid stores the final results in vectors that contain all bus voltage magnitudes and angles:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐕 = analysis.voltage.magnitude\n𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#ACPowerAnalysisTutorials","page":"AC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Once the computation of voltage magnitudes and angles at each bus is completed, various electrical quantities can be determined. JuliaGrid offers the power! function, which enables the calculation of powers associated with buses, branches, and generators. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function stores the computed powers in the rectangular coordinate system. It calculates the following powers related to buses, branches, and generators:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Active Reactive\nInjections mathbfP = P_i mathbfQ = Q_i\nGenerator injections mathbfP_textp = P_textpi mathbfQ_textp = Q_textpi\nShunt elements mathbfP_textsh = P_textshi mathbfQ_textsh = Q_textshi","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Branch Active Reactive\nFrom-bus end flows mathbfP_texti = P_ij mathbfQ_texti = Q_ij\nTo-bus end flows mathbfP_textj = P_ji mathbfQ_textj = Q_ji\nShunt elements mathbfP_texts = P_textsij mathbfP_texts = P_textsij\nSeries elements mathbfP_textl = P_textlij mathbfQ_textl = Q_textlij","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Generator Active Reactive\nOutputs mathbfP_textg = P_textgi mathbfQ_textg = Q_textgi","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-Injections","page":"AC Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive power injections are stored as the vectors mathbfP = P_i and mathbfQ = Q_i, respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏 = analysis.power.injection.active\n𝐐 = analysis.power.injection.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GeneratorPowerInjectionsManual","page":"AC Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The power! function in JuliaGrid also computes the active and reactive power injections from the generators at each bus. The active power supplied by the generators to the buses can be calculated by summing the given generator active powers in the input data, except for the slack bus, which can be determined as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" P_textpi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where P_textdi represents the active power demanded by consumers at the slack bus. The active power injections from the generators at each bus are stored as the vector, denoted by mathbfP_textp = P_textpi, can be obtained using:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The calculation of reactive power injection from the generators at generator or slack buses can be achieved using the subsequent equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_textpi = Q_i + Q_textdi forall i in mathcalN_textpv cup mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"where Q_textdi represents the reactive power demanded by consumers at the corresponding bus. Further, the reactive power injected by the generators at buses from mathcalN_textpq can be calculated by summing the given generator reactive powers in the input data. The vector of these reactive power injections by the generators to the buses, denoted by mathbfQ_textp = Q_textpi, can be retrieved using the following command:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐐ₚ = analysis.power.supply.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Bus-Shunt-Elements","page":"AC Power Flow","title":"Power at Bus Shunt Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the shunt elements at each bus are represented by the vectors mathbfP_textsh = P_textshi and mathbfQ_textsh = Q_textshi. To retrieve these powers in JuliaGrid, use the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₛₕ = analysis.power.shunt.active\n𝐐ₛₕ = analysis.power.shunt.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-Flows","page":"AC Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The resulting active and reactive power flows at each from-bus end are stored as the vectors mathbfP_texti = P_ij and mathbfQ_texti = Q_ij respectively, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ᵢ = analysis.power.from.active\n𝐐ᵢ = analysis.power.from.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The vectors of active and reactive power flows at the to-bus end are stored as mathbfP_textj = P_ji and mathbfQ_textj = Q_ji, respectively, and can be retrieved using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ⱼ = analysis.power.to.active\n𝐐ⱼ = analysis.power.to.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Branch-Shunt-Elements","page":"AC Power Flow","title":"Power at Branch Shunt Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the branch shunt elements at each branch are represented by the vectors mathbfP_texts = P_textsij and mathbfQ_texts = Q_textsij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₛ = analysis.power.charging.active\n𝐐ₛ = analysis.power.charging.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Power-at-Branch-Series-Elements","page":"AC Power Flow","title":"Power at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Active and reactive powers associated with the branch series element at each branch are represented by the vectors mathbfP_textl = P_textlij and mathbfQ_textl = Q_textlij. We can retrieve these values using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₗ = analysis.power.series.active\n𝐐ₗ = analysis.power.series.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#GeneratorPowerOutputsManual","page":"AC Power Flow","title":"Generator Power Outputs","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the output active powers of each generator connected to bus i in mathcalN_textpq cup mathcalN_textpv, the given active power in the input data is utilized. For the generator connected to the slack bus, the output active power is determined using the equation:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" P_textgi = P_i + P_textdi i in mathcalN_textsb","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In the case of multiple generators connected to the slack bus, the first generator in the input data is assigned the obtained value of P_textgi. Then, this amount of power is reduced by the output active power of the other generators.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To retrieve the vector of active power outputs of generators, denoted as mathbfP_textg = P_textgi, i in mathcalS, where the set mathcalS represents the set of generators, users can utilize the following command:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The output reactive powers of each generator located at the bus is obtained as:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":" Q_textgi = Q_i + Q_textdi i in mathcalN","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"If there are multiple generators at the same bus, the reactive power is allocated proportionally among the generators based on their reactive power capabilities.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To retrieve the vector of reactive power outputs of generators, denoted as mathbfQ_textg = Q_textgi, i in mathcalS, users can utilize:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐐ₒ = analysis.power.generator.reactive","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#ACCurrentAnalysisTutorials","page":"AC Power Flow","title":"Current Analysis","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"JuliaGrid offers the current! function, which enables the calculation of currents associated with buses and branches. Here is an example code snippet demonstrating its usage:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"current!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"The function stores the computed currents in the polar coordinate system. It calculates the following currents related to buses and branches:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Bus Magnitude Angle\nInjections mathbfI = I_i bmpsi = psi_i","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Branch Magnitude Angle\nFrom-bus end flows mathbfI_texti = I_ij bmpsi_texti = psi_ij\nTo-bus end flows mathbfI_textj = I_ji bmpsi_textj = psi_ji\nSeries elements mathbfI_textl = I_textlij bmpsi_textl = psi_textlij","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols presented in this section, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-Injections","page":"AC Power Flow","title":"Current Injections","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"In JuliaGrid, complex current injections are stored in the vector of magnitudes denoted as mathbfI = I_i and the vector of angles represented as bmpsi = psi_i. You can retrieve them using the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈 = analysis.current.injection.magnitude\n𝛙 = analysis.current.injection.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-Flows","page":"AC Power Flow","title":"Current Flows","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the vectors of magnitudes mathbfI_texti = I_ij and angles bmpsi_texti = psi_ij for the resulting complex current flows, you can use the following commands:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ᵢ = analysis.current.from.magnitude\n𝛙ᵢ = analysis.current.from.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"Similarly, we can obtain the vectors of magnitudes mathbfI_textj = I_ji and angles bmpsi_textj = psi_ji of the resulting complex current flows using the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ⱼ = analysis.current.to.magnitude\n𝛙ⱼ = analysis.current.to.angle","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"","category":"page"},{"location":"tutorials/acPowerFlow/#Current-at-Branch-Series-Elements","page":"AC Power Flow","title":"Current at Branch Series Elements","text":"","category":"section"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"To obtain the vectors of magnitudes mathbfI_textl = I_textlij and angles bmpsi_textl = psi_textlij of the resulting complex current flows, one can use the following code:","category":"page"},{"location":"tutorials/acPowerFlow/","page":"AC Power Flow","title":"AC Power Flow","text":"𝐈ₗ = analysis.current.series.magnitude\n𝛙ₗ = analysis.current.series.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowTutorials","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To begin, let us generate the PowerSystem type, as illustrated by the following example:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, HiGHS\n@default(template) # hide\n@default(unit) # hide\n\n@labels(Integer)\n\nsystem = powerSystem()\n\naddBus!(system; label = 1, type = 3, angle = 0.17)\naddBus!(system; label = 2, type = 2, active = 0.1, conductance = 0.04)\naddBus!(system; label = 3, type = 1, active = 0.05)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.05, maxFromBus = 0.15)\naddBranch!(system; label = 2, from = 1, to = 3, reactance = 0.01, maxFromBus = 0.10)\naddBranch!(system; label = 3, from = 2, to = 3, reactance = 0.01, maxFromBus = 0.25)\n\n@generator(minActive = 0.0)\naddGenerator!(system; label = 1, bus = 1, active = 3.2, maxActive = 0.5)\naddGenerator!(system; label = 2, bus = 2, active = 0.2, maxActive = 0.3)\n\ncost!(system; label = 1, active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = 2, active = 1, piecewise = [10.85 12.3; 14.77 16.8; 18 18.1])\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Moreover, we identify the set of generators as mathcalS = 1 dots n_textg within the power system:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝒮 = collect(keys(system.generator.label))","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"ukw: Notation\nHere, when referring to a vector mathbfa, we use the notation mathbfa = a_i or mathbfa = a_ij, where a_i represents the element related with bus i in mathcalN or generator i in mathcalS, while a_ij denotes the element related with branch (ij) in mathcalE.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowModelTutorials","page":"DC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the DC optimal power flow, the active power outputs of the generators mathbf P_textg = P_textgi, i in mathcalS, are represented as linear functions of the bus voltage angles bmTheta = theta_i, i in mathcalN. Thus, the optimization variables in this model are the active power outputs of the generators and the bus voltage angles.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow model has the form:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n textminimize sum_i in mathcalS f_i(P_textgi) \n textsubjectto theta_i - theta_texts = 0 i in mathcalN_textsb 3pt\n h_P_i(mathbf P_textg bmTheta) = 0 forall i in mathcalN 3pt\n theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE 3pt\n P_ij^textmin leq h_P_ij(theta_i theta_j) leq P_ij^textmax forall (ij) in mathcalE 3pt\n P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Essentially, the DC optimal power flow is focused on the minimization of the objective function related to the costs associated with the active power output of generators, all while ensuring the satisfaction of various constraints. This optimization task holds a crucial role in the efficient and timely management of electrical power systems. However, it is important to note that the solutions provided by the DC optimal power flow are approximate in nature.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Build-Optimal-Power-Flow-Model","page":"DC Optimal Power Flow","title":"Build Optimal Power Flow Model","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To build the DC optimal power flow model, we must first load the power system and establish the DC model using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"dcModel!(system)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Afterward, the DC optimal power flow model is created using the dcOptimalPowerFlow function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"analysis = dcOptimalPowerFlow(system, HiGHS.Optimizer; active = \"Pg\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Optimization-Variables","page":"DC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Hence, the variables in this model encompass the active power outputs of the generators denoted as mathbfP_textg = P_textgi, where i in mathcalS, and the bus voltage angles represented by bmTheta = theta_i, where i in mathcalN. You can access these variables using the following:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = analysis.method.variable.active\n𝚯 = analysis.method.variable.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Objective-Function","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The objective function represents the sum of the active power cost functions f_i(P_textgi), i in mathcalS, for each generator, where these cost functions can be polynomial or linear piecewise functions. It is important to note that only polynomial cost functions up to the second degree are included in the objective function. If higher-degree polynomials are present, they will be excluded from the objective function by JuliaGrid.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Polynomial-Active-Power-Cost-Function","page":"DC Optimal Power Flow","title":"Polynomial Active Power Cost Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow in JuliaGrid allows the cost function f_i(P_textgi) to be represented as a polynomial of up to the second degree, making it possible to express the cost function as linear or quadratic. The possible representations are as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n f_i(P_textgi) = a_1P_textgi + a_0 \n f_i(P_textgi) = a_2 P_textgi^2 + a_1P_textgi + a_0\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Furthermore, it is worth noting that the function can be given simply as a constant with only the coefficient a_0, which implies that the cost of the generator remains constant regardless of the active power outputs. In conclusion, as illustrated in Figure 1, typical scenarios involve linear or quadratic cost functions, resulting in a best-case scenario for a linear optimization problem and a worst-case scenario for a quadratic optimization problem.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"\n
Figure 1: The polynomial cost functions of generator active power output.
\n ","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"When utilizing the cost! function within JuliaGrid, employing the polynomial keyword results in the polynomial being constructed with coefficients ordered from the highest degree to the lowest. For instance, in the provided case study, we created a quadratic polynomial represented as:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"beginaligned\n f_1(P_textg1) = 11002 P_textg1^2 + 500 P_textg1 + 80\nendaligned","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To access these coefficients, users can utilize the variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"f₁ = system.generator.cost.active.polynomial[1]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Linear-Piecewise-Active-Power-Cost-Function","page":"DC Optimal Power Flow","title":"Linear Piecewise Active Power Cost Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The DC optimal power flow in JuliaGrid offers another option for defining cost functions by using linear piecewise functions as approximations of the polynomial functions, as depicted in Figure 2.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"\n
Figure 2: The linear piecewise cost functions of active power output.
\n ","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To define linear piecewise functions in JuliaGrid, users can utilize the cost! function with the piecewise keyword. The linear piecewise function is constructed using a matrix where each row defines a single point. The first column holds the generator's active power output, while the second column corresponds to the associated cost value. For example, in the provided case study, a linear piecewise function is created and can be accessed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"f₂ = system.generator.cost.active.piecewise[2]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similar to how convex linear piecewise functions are treated in the AC Optimal Power Flow, JuliaGrid adopts a constrained cost variable method for the linear piecewise functions. In this method, the piecewise linear cost function is converted into a series of linear inequality constraints for each segment, which are defined by two adjacent points along the line, along with a helper variable specific to the piecewise function. However, for linear piecewise functions that have only one segment defined by two points, JuliaGrid simplifies it into a standard linear function without requiring a helper variable.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Consequently, for a piecewise cost function denoted as f_i(P_textgi) with k segments (where k 1), the j-th segment, defined by the points P_textgij f_i(P_textgij) and P_textgij+1 f_i(P_textgij+1), is characterized by the following inequality constraints:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"cfracf_i(P_textgij+1) - f_i(P_textgij)P_textgij+1 - P_textgij(P_textgi - P_textgij) + f_i(P_textgij) leq H_i i in mathcalS j = 1dotsk","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where H_i represents the helper variable. To finalize this method, we simply need to include the helper variable H_i in the objective function. This approach efficiently handles linear piecewise cost functions, providing the flexibility to capture nonlinear characteristics while still benefiting from the advantages of linear optimization techniques.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As an example, in the provided case study, the helper variable is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"H₂ = analysis.method.variable.actwise[2]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Lastly, the set of constraints introduced by the linear piecewise cost function is displayed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.piecewise.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Objective-Function-2","page":"DC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As previously explained, the objective function relies on the defined polynomial or linear piecewise cost functions and represents the sum of these costs. In the provided example, the objective function that must be minimized to obtain the optimal values for the active power output of the generators and the bus voltage angles can be accessed using the following code:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Constraint-Functions","page":"DC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In the following section, we will examine the various constraints defined within the DC optimal power flow model.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Slack-Bus-Constraint","page":"DC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The first equality constraint is linked to the slack bus, where the bus voltage angle denoted as theta_i is fixed to a constant value theta_texts. It can be expressed as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"theta_i - theta_texts = 0 i in mathcalN_textsb","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where the set mathcalN_textsb contains the index of the slack bus. To access the equality constraint from the model, we can utilize the variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.slack.angle)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Bus-Active-Power-Balance-Constraints","page":"DC Optimal Power Flow","title":"Bus Active Power Balance Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The second equality constraint in the optimization problem is associated with the active power balance equation:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_i(mathbf P_textg bmTheta) = 0 forall i in mathcalN","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"As elaborated in the Nodal Network Equations section, we can express the equation as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_i(mathbf P_textg bmTheta) = sum_k in mathcalS_i P_textgk - sum_k = 1^n B_ik theta_k - P_textdi - P_textshi - P_texttri","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this equation, the set mathcalS_i subseteq mathcalS encompasses all generators connected to bus i in mathcalN, and P_textgk represents the active power output of the k-th generator within the set mathcalS_i. More precisely, the variable P_textgk represents the optimization variable, as well as the bus voltage angle theta_k.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The constant terms in these equations are determined by the active power demand at bus P_textdi, the active power demanded by the shunt element P_textshi, and power related to the shift angle of the phase transformers P_texttri. The values representing these constant terms mathbfP_textd = P_textdi, mathbfP_textsh = P_textshi, and mathbfP_texttr = P_texttri, i in mathcalN, can be accessed:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = system.bus.demand.active\n𝐏ₛₕ = system.bus.shunt.conductance\n𝐏ₜᵣ = system.model.dc.shiftPower","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.balance.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Bus-Voltage-Angle-Difference-Constraints","page":"DC Optimal Power Flow","title":"Bus Voltage Angle Difference Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraint related to the minimum and maximum bus voltage angle difference between the from-bus and to-bus ends of each branch is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"theta_ij^textmin leq theta_i - theta_j leq theta_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"where theta_ij^textmin represents the minimum, while theta_ij^textmax represents the maximum of the angle difference between adjacent buses. The values representing the voltage angle difference, denoted as bmTheta_textlm = theta_ij^textmin theta_ij^textmax, (ij) in mathcalE, are provided as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝚯ₗₘ = [system.branch.voltage.minDiffAngle system.branch.voltage.maxDiffAngle]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.voltage.angle)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Branch-Active-Power-Flow-Constraints","page":"DC Optimal Power Flow","title":"Branch Active Power Flow Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraint related to active power flow is used to represent thermal limits on power transmission. This constraint is defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"P_ij^textmin leq h_P_ij(theta_i theta_j) leq P_ij^textmax forall (ij) in mathcalE","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The branch flow limits at the from-bus, denoted as mathbfP_textf = P_ij^textmin P_ij^textmax , can be retrieved as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = [system.branch.flow.minFromBus system.branch.flow.maxFromBus]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The active power flow at branch (ij) in mathcalE can be derived using the Branch Network Equations and is given by:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"h_P_ij(theta_i theta_j) = frac1tau_ij x_ij (theta_i - theta_j - phi_ij)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.flow.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Generator-Active-Power-Capability-Constraints","page":"DC Optimal Power Flow","title":"Generator Active Power Capability Constraints","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The inequality constraints associated with the minimum and maximum active power outputs of the generators are defined as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"P_textgi^textmin leq P_textgi leq P_textgi^textmax forall i in mathcalS","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"In this representation, the lower and upper bounds are determined by the vector mathbfP_textm = P_textgi^textmin P_textgi^textmax, i in mathcalS. We can access these bounds using the following variable:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₘ = [system.generator.capability.minActive system.generator.capability.maxActive]","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To retrieve constraints from the model, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"print(analysis.method.constraint.capability.active)","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerFlowSolutionTutorials","page":"DC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"To acquire the output active power of generators and the bus voltage angles, the user must invoke the function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Therefore, to get the vector of output active power of generators mathbfP_textg = P_textgi, i in mathcalS, we can use:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₒ = analysis.power.generator.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Further, the resulting bus voltage angles bmTheta = theta_i, i in mathcalN, are saved in the vector as follows:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝚯 = analysis.voltage.angle","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#DCOptimalPowerAnalysisTutorials","page":"DC Optimal Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"After obtaining the solution from the DC optimal power flow, we can calculate the powers related to buses and branches using the power! function:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"note: Info\nFor a clear comprehension of the equations, symbols provided below, as well as for a better grasp of power directions, please refer to the Unified Branch Model.","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Power-Injections","page":"DC Optimal Power Flow","title":"Power Injections","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Active power injections are stored as the vector mathbfP = P_i, and can be retrieved using the following commands:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏 = analysis.power.injection.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Generator-Power-Injections","page":"DC Optimal Power Flow","title":"Generator Power Injections","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The active power supplied by generators to the buses can be calculated by summing the active power outputs of the generators obtained from the optimal DC power flow. This can be expressed as:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":" P_textpi = sum_k=1^n_textgi P_textgk forall i in mathcalN","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Here, P_textgk represents the active power output of the k-th generator connected to bus i in mathcalN, and n_textgi denotes the total number of generators connected to the same bus. We can obtain the vector of active powers injected by generators into the buses, denoted as mathbfP_textp = P_textpi, using the following command:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ₚ = analysis.power.supply.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/#Power-Flows","page":"DC Optimal Power Flow","title":"Power Flows","text":"","category":"section"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"The resulting from-bus active power flows are stored as the vector mathbfP_texti = P_ij, which can be retrieved using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ᵢ = analysis.power.from.active","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"Similarly, the resulting to-bus active power flows are stored as the vector mathbfP_textj = P_ji, which can be retrieved using:","category":"page"},{"location":"tutorials/dcOptimalPowerFlow/","page":"DC Optimal Power Flow","title":"DC Optimal Power Flow","text":"𝐏ⱼ = analysis.power.to.active","category":"page"},{"location":"manual/pmuStateEstimation/#PMUStateEstimationManual","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To perform linear state estimation solely based on PMU data, the initial requirement is to have the PowerSystem type configured with the AC model, along with the Measurement type storing measurement data. Subsequently, we can formulate either the weighted least-squares (WLS) or the least absolute value (LAV) PMU state estimation model encapsulated within the type PMUStateEstimation using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"pmuStateEstimation,\npmuLavStateEstimation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For resolving the PMU state estimation problem and obtaining bus voltage magnitudes and angles, utilize the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After executing the function solve!, where the user employs the WLS method, the user has the ability to check if the measurement set contains outliers throughout bad data analysis and remove those measurements using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"residualTest!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Moreover, before the creating PMUStateEstimation type, users can initiate an optimal PMU placement algorithm to determine the minimal set of PMUs required for an observable system:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"pmuPlacement.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After obtaining the PMU state estimation solution, JuliaGrid offers post-processing analysis functions for calculating powers and currents associated with buses and branches:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses or branches.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#OptimalPMUPlacementManual","page":"PMU State Estimation","title":"Optimal PMU Placement","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us define the PowerSystem type and perform the AC power flow analysis solely for generating data to artificially create measurement values:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.04)\n\n@generator(reactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 2.1)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:10\n mismatch!(system, analysis)\n solve!(system, analysis)\nend\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Optimal-Solution","page":"PMU State Estimation","title":"Optimal Solution","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon defining the PowerSystem type, JuliaGrid provides the possibility to determine the minimal number of PMUs required for system observability using the pmuPlacement function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using GLPK\n\nplacement = pmuPlacement(system, GLPK.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The placement variable contains data regarding the optimal placement of measurements. In this instance, installing a PMU at Bus 2 renders the system observable:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.bus","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This PMU installed at Bus 2 will measure the bus voltage phasor at the corresponding bus and all current phasors at the branches incident to Bus 2 located at the from-bus or to-bus ends:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"placement.from\nplacement.to","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Optimal PMU Placement for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Measurement-Data","page":"PMU State Estimation","title":"Measurement Data","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Utilizing PMU placement and AC power flow data, which serves as the source for measurement values in this scenario, we can construct the Measurement type as follows:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"device = measurement()\n\n@pmu(label = \"PMU ? (!)\")\nfor (bus, idx) in placement.bus\n Vᵢ, θᵢ = analysis.voltage.magnitude[idx], analysis.voltage.angle[idx]\n addPmu!(system, device; bus = bus, magnitude = Vᵢ, angle = θᵢ)\nend\nfor branch in keys(placement.from)\n Iᵢⱼ, ψᵢⱼ = fromCurrent(system, analysis; label = branch)\n addPmu!(system, device; from = branch, magnitude = Iᵢⱼ, angle = ψᵢⱼ)\nend\nfor branch in keys(placement.to)\n Iⱼᵢ, ψⱼᵢ = toCurrent(system, analysis; label = branch)\n addPmu!(system, device; to = branch, magnitude = Iⱼᵢ, angle = ψⱼᵢ)\nend\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For example, we can observe the obtained set of measurement values:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(device.pmu.label, device.pmu.magnitude.mean, device.pmu.angle.mean)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUWLSStateEstimationSolutionManual","page":"PMU State Estimation","title":"Weighted Least-Squares Estimator","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Let us continue with the previous example, where we defined the PowerSystem and Measurement types. To establish the PMU state estimation model, we will use the pmuStateEstimation function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the PMU state estimation problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR:analysis = pmuStateEstimation(system, device, QR)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain the bus voltage magnitudes and angles, the solve! function can be invoked as shown:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe recommend that readers refer to the tutorial on PMU State Estimation for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Correlated-Measurement-Errors","page":"PMU State Estimation","title":"Correlated Measurement Errors","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In the above approach, we assume that measurement errors from a single PMU are uncorrelated. This assumption leads to the covariance matrix and its inverse matrix (i.e., precision matrix) maintaining a diagonal form:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.precision","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"While this approach is suitable for many scenarios, linear PMU state estimation relies on transforming from polar to rectangular coordinate systems. Consequently, measurement errors from a single PMU become correlated due to this transformation. This correlation results in the covariance matrix, and hence the precision matrix, no longer maintaining a diagonal form but instead becoming a block diagonal matrix.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To accommodate this, users have the option to consider correlation when adding each PMU to the Measurement type. For instance, let us add a new PMU while considering correlation:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 1.01, angle = -0.005, correlated = true)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following this, we recreate the WLS state estimation model:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon inspection, it becomes evident that the precision matrix no longer maintains a diagonal structure:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.precision","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, we can address this new scenario and observe the solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Alternative-Formulation","page":"PMU State Estimation","title":"Alternative Formulation","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such cases, users may opt for an alternative formulation of the WLS state estimation, namely, employing an approach called orthogonal factorization [5, Sec. 3.2].","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This approach is suitable when measurement errors are uncorrelated, and the precision matrix remains diagonal. Therefore, as a preliminary step, we need to eliminate the correlation, as we did previously:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"updatePmu!(system, device; label = \"PMU 5 (Bus 3)\", correlated = false)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Subsequently, by specifying the Orthogonal argument in the pmuStateEstimation function, JuliaGrid implements a more robust approach to obtain the WLS estimator, which proves particularly beneficial when substantial differences exist among measurement variances:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis = pmuStateEstimation(system, device, Orthogonal)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Print-Results-in-the-REPL","page":"PMU State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\n@default(unit) # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Save-Results-to-a-File","page":"PMU State Estimation","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nWe also provide functions to print or save state estimation results, such as estimated values and residuals. For more details, users can consult the Power and Current Analysis section of this manual.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUBadDataDetectionManual","page":"PMU State Estimation","title":"Bad Data Processing","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After acquiring the WLS solution using the solve! function, users can conduct bad data analysis employing the largest normalized residual test. Continuing with our defined power system and measurement set, let us introduce a new phasor measurement. Upon proceeding to find the solution for this updated state:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"addPmu!(system, device; bus = \"Bus 3\", magnitude = 3.2, angle = 0.0, noise = false)\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Following the solution acquisition, we can verify the presence of erroneous data. Detection of such data is determined by the threshold keyword. If the largest normalized residual's value exceeds the threshold, the measurement will be identified as bad data and consequently removed from the PMU state estimation model:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier = residualTest!(system, device, analysis; threshold = 4.0)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can examine the data obtained from the bad data analysis:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"outlier.detect\noutlier.maxNormalizedResidual\noutlier.label","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Hence, upon detecting bad data, the detect variable will hold true. The maxNormalizedResidual variable retains the value of the largest normalized residual, while the label contains the label of the measurement identified as bad data. JuliaGrid will mark the respective phasor measurement as out-of-service within the Measurement type.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Moreover, JuliaGrid will adjust the coefficient matrix and mean vector within the PMUStateEstimation type based on measurements now designated as out-of-service. To optimize the algorithm's efficiency, JuliaGrid resets non-zero elements to zero in the coefficient matrix and mean vector, effectively removing the impact of the corresponding measurement on the solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"analysis.method.mean\nanalysis.method.coefficient","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After removing bad data, a new estimate can be computed without considering this specific phasor measurement:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Bad Data Processing for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMULAVtateEstimationSolutionManual","page":"PMU State Estimation","title":"Least Absolute Value Estimator","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data processing procedures [5, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To obtain an LAV estimator, users need to employ one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using Ipopt\nusing JuMP # hide\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Setup-Starting-Primal-Values","page":"PMU State Estimation","title":"Setup Starting Primal Values","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"In JuliaGrid, the assignment of starting primal values for optimization variables takes place when the solve! function is executed. Starting primal values are determined based on the voltage fields within the PMUStateEstimation type. By default, these values are initially established using the initial bus voltage magnitudes and angles from PowerSystem type:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users have the flexibility to customize these values according to their requirements, and they will be utilized as the starting primal values when executing the solve! function. It is important to note that JuliaGrid utilizes the provided data to set starting primal values in the rectangular coordinate system.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Solution","page":"PMU State Estimation","title":"Solution","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To solve the formulated LAV state estimation model, simply execute the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Upon obtaining the solution, access the bus voltage magnitudes and angles using:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nWe suggest that readers refer to the tutorial on Least Absolute Value Estimation for insights into the implementation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUMeasurementsAlterationManual","page":"PMU State Estimation","title":"Measurement Set Update","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After establishing the Measurement type using the measurement function, users gain the capability to incorporate new measurement devices or update existing ones.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Once updates are completed, users can seamlessly progress towards generating the PMUStateEstimation type using the pmuStateEstimation or pmuLavStateEstimation function. Ultimately, resolving the PMU state estimation is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.98, angle = -0.023)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 0.5, angle = -0.05)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for the model\nsolve!(system, analysis)\n\naddPmu!(system, device; to = \"Branch 2\", magnitude = 0.5, angle = 3.1)\nupdatePmu!(system, device; label = \"PMU 1\", varianceMagnitude = 1e-8)\nupdatePmu!(system, device; label = \"PMU 3\", statusMagnitude = 0, statusAngle = 0)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for new model\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nThis concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUStateEstimationUpdateManual","page":"PMU State Estimation","title":"State Estimation Update","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"An advanced methodology involves users establishing the PMUStateEstimation type using pmuStateEstimation or pmuLavStateEstimation just once. After this initial setup, users can seamlessly modify existing measurement devices without the need to recreate the PMUStateEstimation type.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"This advancement extends beyond the previous scenario where recreating the Measurement type was unnecessary, to now include the scenario where PMUStateEstimation also does not need to be recreated.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"tip: Tip\nThe addition of new measurements after the creation of PMUStateEstimation is not practical in terms of reusing the PMUStateEstimation type. Instead, we recommend that users create a final set of measurements and then utilize update functions to manage devices, either putting them in-service or out-of-service throughout the process.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can modify the prior example to achieve the same model without establishing PMUStateEstimation twice:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement() # <- Initialize the Measurement instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\n@pmu(label = \"PMU ?\")\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.98, angle = -0.023)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 0.5, angle = -0.05)\naddPmu!(system, device; to = \"Branch 2\", magnitude = 0.5, angle = 3.1, statusAngle = 0)\n\nanalysis = pmuStateEstimation(system, device) # <- Build PMUStateEstimation for the model\nsolve!(system, analysis)\n\nupdatePmu!(system, device, analysis; label = \"PMU 1\", varianceMagnitude = 1e-8)\nupdatePmu!(system, device, analysis; label = \"PMU 3\", statusMagnitude = 0, statusAngle = 0)\nupdatePmu!(system, device, analysis; label = \"PMU 4\", statusAngle = 1)\n\n# <- No need for re-build; we have already updated the existing PMUStateEstimation instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nThis concept removes the need to rebuild both the Measurement and the PMUStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of employing the WLS model, JuliaGrid can reuse the symbolic factorizations of LU or LDLt, provided that the nonzero pattern of the gain matrix remains unchanged.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#PMUSEPowerCurrentAnalysisManual","page":"PMU State Estimation","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"After obtaining the solution from the PMU state estimation, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the model for which we obtained the PMU state estimation solution:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, susceptance = 0.002)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1, reactive = 0.01)\naddBus!(system; label = \"Bus 3\", type = 1, active = 2.5, reactive = 0.2)\n\n@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.05)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.03)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.3)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.0, angle = 0.0)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.97, angle = -0.051)\naddPmu!(system, device; from = \"Branch 2\", magnitude = 1.66, angle = -0.15)\naddPmu!(system, device; to = \"Branch 2\", magnitude = 1.67, angle = 2.96)\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can now utilize the provided functions to compute powers and currents:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For instance, if we want to show the active power injections and the from-bus current magnitudes, we can employ the following code:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.magnitude)","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"note: Info\nTo better understand the powers and currents associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on PMU State Estimation.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Print-Results-in-the-REPL-2","page":"PMU State Estimation","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Users can utilize any of the print functions outlined in the Print API. For example, to print state estimation data related to PMUs, we can use:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"@voltage(pu, deg, V)\nshow = Dict(\"Voltage Angle\" => false, \"Current Angle\" => false)\nprintPmuData(system, device, analysis; show)\n@default(unit) # hide","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Save-Results-to-a-CSV-File","page":"PMU State Estimation","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"using CSV\n\nio = IOBuffer()\nprintPmuData(system, device, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Injection","page":"PMU State Estimation","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Injection-from-Generators","page":"PMU State Estimation","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Shunt-Element","page":"PMU State Estimation","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-Flow","page":"PMU State Estimation","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Charging-Admittances","page":"PMU State Estimation","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Active-and-Reactive-Power-at-Series-Impedance","page":"PMU State Estimation","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Injection","page":"PMU State Estimation","title":"Current Injection","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Flow","page":"PMU State Estimation","title":"Current Flow","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"","category":"page"},{"location":"manual/pmuStateEstimation/#Current-Through-Series-Impedance","page":"PMU State Estimation","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/pmuStateEstimation/","page":"PMU State Estimation","title":"PMU State Estimation","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowManual","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To perform the DC power flow, we first need to have the PowerSystem type that has been created with the DC model. Following that, we can construct the power flow model encapsulated within the DCPowerFlow type by employing the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"dcPowerFlow.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To solve the DC power flow problem and acquire bus voltage angles, make use of the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution for DC power flow, JuliaGrid offers a post-processing analysis function to compute active powers associated with buses, branches, and generators:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers for individual buses, branches, or generators.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCBusTypeModificationManual","page":"DC Power Flow","title":"Bus Type Modification","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"During the initialization process, the designated slack bus, which is initially set, undergoes examination and can be altered using the dcPowerFlow function. Here is an example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"system = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2)\naddBus!(system; label = \"Bus 3\", type = 2)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 3\")\n\ndcModel!(system)\nanalysis = dcPowerFlow(system)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In this example, the slack bus (type = 3) corresponds to the Bus 1. However, this bus does not have an in-service generator connected to it. JuliaGrid considers this a mistake and attempts to assign a new slack bus from the available generator buses (type = 2) that have connected in-service generators. In this particular example, the Bus 3 will become the new slack bus. As a result, we can observe the updated array of bus types:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 2, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; bus = \"Bus 3\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, system.bus.layout.type)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThe bus that is defined as the slack bus (type = 3) but lacks a connected in-service generator will have its type changed to the demand bus (type = 1). Meanwhile, the first generator bus (type = 2) with an in-service generator connected to it will be assigned as the new slack bus (type = 3).","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowSolutionManual","page":"DC Power Flow","title":"Power Flow Solution","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To solve the DC power flow problem using JuliaGrid, we start by creating the PowerSystem type and defining the DC model with the dcModel! function. Here is an example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The dcPowerFlow function can be used to establish the DC power flow problem:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"analysis = dcPowerFlow(system)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"tip: Tip\nHere, the user triggers LU factorization as the default method for solving the DC power flow problem. However, the user also has the option to select alternative factorization methods such as LDLt or QR, for instance:analysis = dcPowerFlow(system, LDLt)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To obtain the bus voltage angles, we can call the solve! function as follows:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"solve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Once the solution is obtained, the bus voltage angles can be accessed using:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, analysis.voltage.angle)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nFor implementation insights, we suggest referring to the tutorial on DC Power Flow Analysis.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Print-Results-in-the-REPL","page":"DC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users have the option to print the results in the REPL using any units that have been configured, such as:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@voltage(pu, deg, V)\nprintBusData(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Next, users can easily customize the print results for specific buses, for example:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"printBusData(system, analysis; label = \"Bus 1\", header = true)\nprintBusData(system, analysis; label = \"Bus 2\")\nprintBusData(system, analysis; label = \"Bus 3\", footer = true)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Save-Results-to-a-File","page":"DC Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusData(system, analysis, file)\nend","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Save-Results-to-a-CSV-File","page":"DC Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusData(system, analysis, io; style = false)\nCSV.write(\"bus.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerSystemAlterationManual","page":"DC Power Flow","title":"Power System Update","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After establishing the PowerSystem type using the powerSystem function and configuring the DC model with dcModel!, users gain the capability to incorporate new branches and generators. Furthermore, they can adjust buses, branches, and generators.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Once updates are completed, users can progress towards generating the DCPowerFlow type using the dcPowerFlow function. Ultimately, resolving the DC power flow is achieved through the utilization of the solve! function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 2.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the defined power system\nsolve!(system, analysis)\n\nupdateBus!(system; label = \"Bus 2\", active = 0.4)\n\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system; label = \"Branch 1\", status = 0)\n\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.5)\nupdateGenerator!(system; label = \"Generator 1\", active = 1.9)\n\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the updated power system\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate the PowerSystem within the dc field from the beginning when implementing changes to the existing power system.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerFlowUpdateManual","page":"DC Power Flow","title":"Power Flow Update","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"An advanced methodology involves users establishing the DCPowerFlow type using dcPowerFlow just once. After this initial setup, users can integrate new branches and generators, and also have the capability to modify buses, branches, and generators, all without the need to recreate the DCPowerFlow type.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"This advancement extends beyond the previous scenario where recreating the PowerSystem and DC model was unnecessary, to now include the scenario where DCPowerFlow also does not need to be recreated. Such efficiency can be particularly advantageous in cases where JuliaGrid can reuse nodal matrix factorization.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"By modifying the previous example, we observe that we now create the DCPowerFlow type only once:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem() # <- Initialize the PowerSystem instance\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 2, active = 2.1)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\ndcModel!(system)\nanalysis = dcPowerFlow(system) # <- Build DCPowerFlow for the defined power system\nsolve!(system, analysis)\n\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.4)\n\naddBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\nupdateBranch!(system, analysis; label = \"Branch 1\", status = 0)\n\naddGenerator!(system, analysis; label = \"Generator 2\", bus = \"Bus 2\", active = 1.5)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 1.9)\n\n# <- No need for re-build; we have already updated the existing DCPowerFlow instance\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nThis concept removes the need to restart and recreate both the PowerSystem within the dc field and the DCPowerFlow from the beginning when implementing changes to the existing power system. Additionally, JuliaGrid can reuse symbolic factorizations of LU or LDLt, as long as the nonzero pattern of the nodal matrix remains consistent between power system configurations.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Reusing-Matrix-Factorization","page":"DC Power Flow","title":"Reusing Matrix Factorization","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Drawing from the preceding example, our focus now shifts to finding a solution involving modifications that entail adjusting the active power demand at Bus 2, introducing a new generator at Bus 2, and fine-tuning the output power of Generator 1. It is important to note that these adjustments do not impact the branches, leaving the nodal matrix unchanged. To resolve this updated system, users can simply execute the solve! function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"\nupdateBus!(system, analysis; label = \"Bus 2\", active = 0.2)\naddGenerator!(system, analysis; label = \"Generator 3\", bus = \"Bus 2\", active = 0.3)\nupdateGenerator!(system, analysis; label = \"Generator 1\", active = 2.1)\n\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nIn this scenario, JuliaGrid will recognize instances where the user has not modified branch parameters affecting the nodal matrix. Consequently, JuliaGrid will leverage the previously performed nodal matrix factorization, resulting in a significantly faster solution compared to recomputing the factorization.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Limitations","page":"DC Power Flow","title":"Limitations","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"The dcPowerFlow function oversees bus type validations, as detailed in the Bus Type Modification section. Consequently, if a user intends to change the slack bus or leaves an existing slack bus without a generator, proceeding directly to the solve! function is not feasible.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"In these instances, JuliaGrid will raise an error:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 1\", status = 0)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Now, the user must execute the dcPowerFlow function instead of attempting to reuse the DCPowerFlow type:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"updateGenerator!(system; label = \"Generator 1\", status = 0)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nAfter creating the PowerSystem and DCPowerFlow types, users can add or modify buses, branches, and generators before directly using the solve! function. JuliaGrid automatically executes the necessary functions when adjustments lead to a valid solution. However, if modifications are incompatible, like changing the slack bus, JuliaGrid raises an error to prevent misleading outcomes, ensuring accuracy.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#DCPowerAnalysisManual","page":"DC Power Flow","title":"Power Analysis","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"After obtaining the solution, we can calculate powers related to buses, branches, and generators using the power! function. For example, let us consider the power system for which we obtained the DC power flow solution:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\naddBus!(system; label = \"Bus 1\", type = 3)\naddBus!(system; label = \"Bus 2\", type = 1, active = 0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.05)\n\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.05)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.01)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.01)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2)\n\nanalysis = dcPowerFlow(system)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Now we can calculate the active powers using the following function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"power!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Next, let us convert the base power unit to megavolt-amperes (MVA):","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@base(system, MVA, V)\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, here are the calculated active power values in megawatts (MW) corresponding to buses and branches:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"print(system.bus.label, system.base.power.value * analysis.power.injection.active)\nprint(system.branch.label, system.base.power.value * analysis.power.from.active)","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"note: Info\nTo better understand the powers associated with buses, branches, and generators that are calculated by the power! function, we suggest referring to the tutorials on DC Power Flow Analysis.","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Print-Results-in-the-REPL-2","page":"DC Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, users have the option to print the results in the REPL using any units that have been configured:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"@power(MW, pu, pu)\nprintBranchData(system, analysis)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Injection","page":"DC Power Flow","title":"Active Power Injection","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To calculate active power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Injection-from-Generators","page":"DC Power Flow","title":"Active Power Injection from Generators","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"To calculate active power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = supplyPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Active-Power-Flow","page":"DC Power Flow","title":"Active Power Flow","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Similarly, we can compute the active power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = fromPower(system, analysis; label = \"Branch 2\")\nactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"","category":"page"},{"location":"manual/dcPowerFlow/#Generator-Active-Power-Output","page":"DC Power Flow","title":"Generator Active Power Output","text":"","category":"section"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"Finally, we can compute the active power output of a particular generator using the function:","category":"page"},{"location":"manual/dcPowerFlow/","page":"DC Power Flow","title":"DC Power Flow","text":"active = generatorPower(system, analysis; label = \"Generator 1\")\n@voltage(pu, pu, V) # hide\n@power(pu, pu, pu) # hide","category":"page"},{"location":"tutorials/measurementModel/#MeasurementModelTutorials","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us begin by examining a power system. To do that, we will construct one as shown below:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = 1)\naddBus!(system; label = 2)\naddBus!(system; label = 3)\n\n@branch(reactance = 0.03)\naddBranch!(system; label = 1, from = 1, to = 2)\naddBranch!(system; label = 2, from = 1, to = 3)\naddBranch!(system; label = 3, from = 2, to = 3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To review, we can conceptualize the bus/branch model as the graph denoted by mathcalG = (mathcalN mathcalE), where we have the set of buses mathcalN = 1 dots n, and the set of branches mathcalE subseteq mathcalN times mathcalN within the power system:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒩 = collect(keys(system.bus.label))\nℰ = [𝒩[system.branch.layout.from] 𝒩[system.branch.layout.to]]","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Our goal is to monitor the power system, and this process involves collecting measurement data for various electrical quantities distributed throughout the power system.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Power-System-Monitoring","page":"Measurement Model","title":"Power System Monitoring","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Measurement data is obtained through two main technologies: SCADA (Supervisory Control and Data Acquisition) and WAMS (Wide Area Measurement System). These technologies enable the collection of a wide range of measurements distributed throughout the power system. This extensive dataset allows us to employ state estimation algorithms to obtain the present state of the power system, in contrast to power flow algorithms, which are typically used for offline analyses. To commence, we will represent the entire set of measurement devices as mathcalM.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"SCADA provides legacy measurements with low sampling rates, making them unsuitable for capturing real-time system dynamics. It provides a snapshot of the power system's state, with delays measured in seconds and minutes. These legacy measurement devices, subsets of the set mathcalM, include:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"a set of voltmeters mathcalV for measuring bus voltage magnitudes,\na set of ammeters mathcalI for measuring branch current magnitudes,\na set of wattmeters mathcalP for active power injection and flow measurements,\na set of varmeters mathcalQ for reactive power injection and flow measurements.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In contrast, WAMS technology utilizes PMUs (Phasor Measurement Units) to provide data with high sampling rates, typically ranging between 10 and 20 ms, facilitating real-time monitoring of the system. Therefore, PMUs expand the set mathcalM as follows:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"a set of PMUs barmathcalP for bus voltage and branch current phasor measurements.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"ukw: Notation\nIn this section, when referring to a vector mathbfa, we use the notation mathbfa = a_i, where a_i represents the element associated measurement i in mathcalM.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Measurement-Model","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The measurement model, as defined by the set mathcalM, can be expressed as a system of equations [12]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" mathbfz=mathbfh(mathbf x) + mathbfu","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"where mathbf x=x_1dotsx_n^T is the vector of state variables, mathbfh(mathbfx)= h_1(mathbfx), dots, h_k(mathbfx)^T is the vector of measurement functions, mathbfz = z_1dotsz_k^mathrmT is the vector of measurement values, and mathbfu = u_1dotsu_k^mathrmT is the vector of measurement errors. In the context of transmission grids, this model is often an overdetermined system of equations (ks) [13, Sec. 2.1].","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"These errors are assumed to follow a Gaussian distribution with a zero-mean and covariance matrix bm Sigma. The diagonal elements of bm Sigma correspond to the measurement variances mathbfv = v_1dotsv_k^T, while the off-diagonal elements represent the covariances between the measurement errors mathbfw = w_1dotsw_k^T. These covariances exist only if PMUs are observed in rectangular coordinates and correlation is required.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Gaussian-Probability-Density-Function","page":"Measurement Model","title":"Gaussian Probability Density Function","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Each legacy measurement and each magnitude or angle measurement from PMUs is associated with a measured value z_i, a measurement error u_i, and a measurement function h_i(mathbfx). Assuming that measurement errors u_i follow a zero mean Gaussian distribution, the probability density function associated with the i-th measurement is proportional to:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" mathcalN(z_imathbfxv_i) propto expBiggcfracz_i-h_i(mathbfx)^22v_iBigg","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"where v_i is the measurement variance defined by the measurement error u_i, and the measurement function h_i(mathbfx) connects the vector of state variables mathbfx to the value of the i-th measurement.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Artificial-Generation-of-Measurement-Values","page":"Measurement Model","title":"Artificial Generation of Measurement Values","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When defining the system of equations, it is essential to have measurement values represented by mathbfz. In JuliaGrid, users have the option to either directly specify measurement values or artificially generate the vector mathbfz. The artificial generation process involves setting the keyword noise = true, which introduces white Gaussian noise with variances v_1 dots v_k added to the provided values e_1 dots e_k, typically representing the exact values of the respective electrical quantities:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" epsilon_i sim mathcalN(0v_i) 5pt\n z_i = e_i + epsilon_i","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Voltmeters","page":"Measurement Model","title":"Voltmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A voltmeter V_i in mathcalV measures the bus voltage magnitude at bus i in mathcalN. Let us introduce two voltmeters that measure voltage magnitudes at the first and third bus. For the first voltmeter, we directly pass the measurement value, while for the second voltmeter, we generate the measurement value artificially:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!(system, device; label = \"V₁\", bus = 1, magnitude = 1.1, variance = 1e-3)\naddVoltmeter!(system, device; label = \"V₃\", bus = 3, magnitude = 1.0, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of voltmeters mathcalV subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒱 = collect(keys(device.voltmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of voltmeters defines vectors of measurement values denoted as mathbfz_mathcalV = z_i and variances denoted as mathbfv_mathcalV = v_i, where i in mathcalV, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ᵥ = device.voltmeter.magnitude.mean\n𝐯ᵥ = device.voltmeter.magnitude.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Ammeters","page":"Measurement Model","title":"Ammeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"An ammeter I_ij in mathcalI measures the magnitude of branch current at the from-bus end of the branch (ij) in mathcalE. Let us add this type of ammeter at the first branch between buses 1 and 2:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(system, device; label = \"I₁₂\", from = 1, magnitude = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Additionally, an ammeter can measure the branch current magnitude at the to-bus end of the branch (ij) in mathcalE, denoted as I_ji in mathcalI. For example, we can include this type of ammeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addAmmeter!(system, device; label = \"I₂₁\", to = 1, magnitude = 0.2, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of ammeters mathcalI subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"ℐ = collect(keys(device.ammeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of ammeters defines vectors of measurement values denoted as mathbfz_mathcalI = z_i and variances denoted as mathbfv_mathcalI = v_i, where i in mathcalI, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₒ = device.ammeter.magnitude.mean\n𝐯ₒ = device.ammeter.magnitude.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Wattmeters","page":"Measurement Model","title":"Wattmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A wattmeter P_i in mathcalP measures the active power injection at bus i in mathcalN. Hence, let us add it to the second bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₂\", bus = 2, active = 0.1, variance = 1e-4)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a wattmeter denoted as P_ij in mathcalP measures the active power flow at the from-bus end of the branch (ij) in mathcalE. Let us add this type of wattmeter at the second branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₁₃\", from = 2, active = 0.2, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a wattmeter can also measure the active power flow at the to-bus end of the branch (ij) in mathcalE, denoted as P_ji in mathcalP. For example, we can include this type of wattmeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addWattmeter!(system, device; label = \"P₃₁\", to = 2, active = 0.3, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of wattmeters mathcalP subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒫 = collect(keys(device.wattmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of wattmeters defines vectors of measurement values denoted as mathbfz_mathcalP = z_i and variances denoted as mathbfv_mathcalP = v_i, where i in mathcalP, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₚ = device.wattmeter.active.mean\n𝐯ₚ = device.wattmeter.active.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#Varmeters","page":"Measurement Model","title":"Varmeters","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A varmeter Q_i in mathcalQ measures the reactive power injection at bus i in mathcalN. Hence, let us add it to the first bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₁\", bus = 1, reactive = 0.01, variance = 1e-2)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a varmeter denoted as Q_ij in mathcalQ measures the reactive power flow at the from-bus end of the branch (ij) in mathcalE. Let us add this type of varmeter at the first branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₁₂\", from = 1, reactive = 0.02, variance = 1e-3)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a varmeter can also measure the reactive power flow at the to-bus end of the branch (ij) in mathcalE, denoted as Q_ji in mathcalQ. For example, we can include this type of varmeter at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVarmeter!(system, device; label = \"Q₂₁\", to = 1, reactive = 0.03, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of varmeters mathcalQ subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒬 = collect(keys(device.varmeter.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of varmeters defines vectors of measurement values denoted as mathbfz_mathcalQ = z_i and variances denoted as mathbfv_mathcalQ = v_i, where i in mathcalQ, and can be accessed through the following variables:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝐳ₒ = device.varmeter.reactive.mean\n𝐯ₒ = device.varmeter.reactive.variance","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#PMUs","page":"Measurement Model","title":"PMUs","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"PMUs measure voltage and current phasors in the polar coordinate system, thus each PMU output is represented by magnitude and angle along with corresponding variances [14, Sec. 5.6]. When installed on buses, they measure bus voltage phasors, while on branches, they measure current phasors.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"A PMU (V_i theta_i) in barmathcalP measures the voltage phasor at bus i in mathcalN. Let us integrate this type of PMU at the first bus:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"V₁, θ₁\", bus = 1, magnitude = 1, angle = 0, noise = true)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, a PMU (I_ij psi_ij) in barmathcalP measures the branch current magnitude at the from-bus end of the branch (ij) in mathcalE. Let us add this type of PMU at the first branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"I₁₂, ψ₁₂\", from = 1, magnitude = 0.2, angle = -0.1)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, a PMU can measure the branch current magnitude at the to-bus end of the branch (ij) in mathcalE, denoted as (I_ji psi_ji) in barmathcalP. For example, let us include this type of PMU at the same branch:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addPmu!(system, device; label = \"I₂₁, ψ₂₁\", to = 1, magnitude = 0.3, angle = -0.2)\nnothing # hide","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Consequently, we establish the set of PMUs barmathcalP subset mathcalM:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"𝒫̄ = collect(keys(device.pmu.label))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This set of PMUs establishes vectors representing measurement magnitudes and angles mathbfz_barmathcalP = z_i z_j, along with their corresponding variances mathbfv_barmathcalP = v_i v_j, where (i j) in barmathcalP. These values can be accessed as:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"pmu = device.pmu;\n\n𝐳ₚ = collect(Iterators.flatten(zip(pmu.magnitude.mean, pmu.angle.mean)))\n𝐯ₚ = collect(Iterators.flatten(zip(pmu.magnitude.variance, pmu.angle.variance)))","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nPMUs can be handled in state estimation algorithms according to our definition in polar coordinate systems. However, they can also be processed in rectangular coordinates, where we observe the real and imaginary parts of the phasor measurements rather than magnitude and angle. Further details can be found in tutorials that describe specific state estimation analyses.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"tutorials/measurementModel/#State-Estimation","page":"Measurement Model","title":"State Estimation","text":"","category":"section"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"After establishing the measurement model, which includes specifying measurement values, variances, the locations of measurement devices, and known power system network parameters, the subsequent step involves the process of state estimation. State estimation is a component of energy management systems and typically encompasses network topology processing, observability analysis, state estimation algorithms, and bad data analysis.","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The primary goal of state estimation algorithms is to determine state variables, often associated with bus voltages. Therefore, by representing the vector of state variables as mathbfx and the vector of noisy measurement values as mathbfz, we can effectively describe the state estimation problem using the following conditional probability equation:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":" \t\tp(mathbfxmathbfz)= cfracp(mathbfzmathbfx)p(mathbfx)p(mathbfz)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"If we assume that the prior probability distribution p(mathbfx) is uniform and that p(mathbfz) does not depend on mathbfx, the maximum a posteriori solution simplifies to the maximum likelihood solution, as shown below [15]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbfx = mathrmargmax_mathbfxp(mathbfxmathbfz) =\n\tmathrmargmax_mathbfxp(mathbfzmathbfx) = mathrmargmax_mathbfxmathcalL(mathbfzmathbfx)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"We can find this solution by maximizing the likelihood function mathcalL(mathbfzmathbfx), which is defined based on the likelihoods of k independent measurements:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbf x = mathrmarg max_mathbfxmathcalL(mathbfzmathbfx)=\n\tmathrmarg max_mathbfx prod_i=1^k mathcalN(z_imathbfxv_i)","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"It can be demonstrated that the solution to the maximum a posteriori problem can be obtained by solving the following optimization problem, commonly referred to as the weighted least-squares problem [9, Sec. 9.3]:","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"\thatmathbf x = mathrmargmin_mathbfx sum_i=1^kcfracz_i-h_i(mathbf x)^2v_i","category":"page"},{"location":"tutorials/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The state estimate, denoted as hatmathbf x, resulting from the solution to the above optimization problem, is known as the weighted least-squares estimator. Both the maximum likelihood and weighted least-squares estimators are equivalent to the maximum a posteriori solution [15, Sec. 8.6].","category":"page"},{"location":"manual/measurementModel/#MeasurementModelManual","page":"Measurement Model","title":"Measurement Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The JuliaGrid supports the type Measurement to preserve measurement data, with the following fields: voltmeter, ammeter, wattmeter, varmeter, and pmu. These fields contain information pertaining to measurements such as bus voltage magnitude, branch current magnitude, active power flow and injection, reactive power flow and injection measurements, and measurements of bus voltage and branch current phasors.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The type Measurement can be created using a function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"measurement.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid supports two modes for populating the Measurement type: using built-in functions or using HDF5 files.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To work with HDF5 files, JuliaGrid provides the function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"saveMeasurement.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once the Measurement type has been established, we can incorporate voltmeters, ammeters, wattmeters, varmeters, and phasor measurement units (PMUs) using the following functions:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"addVoltmeter!,\naddAmmeter!,\naddWattmeter!,\naddVarmeter!,\naddPmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Also, JuliaGrid provides macros @voltmeter, @ambmeter, @wattmeter, @varmeter, and @pmu to define templates that aid in creating measurement devices. These templates help avoid entering the same parameters repeatedly.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nIt is important to note that measurement devices associated with branches can only be incorporated if the branch is in-service. This reflects JuliaGrid's approach to mimic a network topology processor, where logical data analysis configures the energized components of the power system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, it is feasible to modify the parameters of measurement devices. When these functions are executed, all relevant fields within the Measurement type will be automatically updated. These functions include:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVoltmeter!,\nupdateAmmeter!,\nupdateWattmeter!,\nupdateVarmeter!,\nupdatePmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nThe functions for updating measurement devices serve a dual purpose. While their primary function is to modify the Measurement type, they are also designed to accept various analysis models like AC or DC state estimation models. When feasible, these functions not only modify the Measurement type but also adapt the analysis model, often resulting in improved computational efficiency. Detailed instructions on utilizing this feature can be found in dedicated manuals for specific analyses.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Finally, the user has the capability to randomly alter the measurement set by activating or deactivating devices through the following function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, we provide users with the ability to modify each specific measurement set by utilizing the functions:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusVoltmeter!,\nstatusAmmeter!,\nstatusWattmeter!,\nstatusVarmeter!,\nstatusPmu!.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#BuildMeasurementModelManual","page":"Measurement Model","title":"Build Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The measurement function generates the Measurement type and requires a string-formatted path to HDF5 files as input. Alternatively, the Measurement can be created without any initial data by initializing it as empty, allowing the user to construct the measurements from scratch.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#HDF5-File","page":"Measurement Model","title":"HDF5 File","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In order to use the HDF5 file as input to create the Measurement type, it is necessary to have saved the data using the saveMeasurement function beforehand. Let us say we saved the measurements as measurements14.h5 in the directory C:\\hdf5. Then, the following code can be used to construct the Measurement type:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device = measurement(\"C:/hdf5/measurements14.h5\")","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Model-from-Scratch","page":"Measurement Model","title":"Model from Scratch","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To start building a model from the ground up, the initial step involves constructing a power system, which facilitates the addition of measurement devices to buses or branches. As an illustration:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.2, variance = 1e-4, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, we have created the voltmeter responsible for measuring the bus voltage magnitude at Bus 1, with associated mean and variance values expressed in per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, we have established the wattmeter to measure the active power flow at the from-bus end of Branch 1, with corresponding mean and variance values also expressed in per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nThe measurement values (i.e., means) can be generated by adding white Gaussian noise with specified variance values to perturb the original values. This can be achieved by setting noise = true within the functions used for adding devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#SaveMeasurementModelManual","page":"Measurement Model","title":"Save Model","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once the Measurement type has been created using one of the methods outlined in Build Model, the current data can be stored in the HDF5 file by using saveMeasurement function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"saveMeasurement(device; path = \"C:/hdf5/measurement.h5\")","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"All electrical quantities saved in the HDF5 file are in per-units and radians.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddVoltmeterManual","page":"Measurement Model","title":"Add Voltmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"We have the option to add voltmeters to a loaded measurement type or to one created from scratch. As an example, we can initiate the Measurement type and then incorporate voltmeters by utilizing the addVoltmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 0.9, variance = 1e-4)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have established two voltmeters designed to measure the bus voltage magnitude at Bus 1. In the case of the second voltmeter, the measurement value is generated internally by introducing white Gaussian noise with the variance added to the magnitude value. As a result, we obtain the following data:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addVoltmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and variance keywords are expected to be provided in per-units (pu). However, users have the flexibility to specify these values in volts (V) if they prefer. For instance, consider the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\n@voltage(kV, rad, V)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = sqrt(3) * 135e3)\n\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 121.5, variance = 0.0135)\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 135, variance = 0.135, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have chosen to specify magnitude and variance in kilovolts (kV). It is important to note that even though we have used kilovolts as the input units, these keywords will still be stored in the per-units:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.voltmeter.magnitude.mean device.voltmeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWhen users choose to input data in volts, measurement values and variances are related to line-to-neutral voltages, while the base values are defined for line-to-line voltages. Therefore, a conversion using sqrt3 is necessary. For more information, refer to the Per-Unit System section.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the voltmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printVoltmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddAmmeterManual","page":"Measurement Model","title":"Add Ammeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users can introduce ammeters into either an existing measurement type or one that they create from the ground up by making use of the addAmmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 0.8, variance = 1e-3)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 0.9, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario, we have established one ammeter to measure the branch current magnitude at the from-bus end of Branch 1, as indicated by the use of the from keyword. Similarly, we have added an ammeter to measure the branch current magnitude at the to-bus end of the branch by utilizing the to keyword.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first ammeter, we assume that the measurement value is already known, defined by the magnitude. In contrast, for the second ammeter, the measurement value is generated by adding white Gaussian noise with the variance to the magnitude value. These actions result in the following outcomes:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.ammeter.magnitude.mean device.ammeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addAmmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-2","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and variance keywords are expected to be provided in per-unit (pu). However, users have the flexibility to express these values in amperes (A) if they prefer. Take a look at the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@current(A, rad)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 135e3)\naddBus!(system; label = \"Bus 2\", base = 135e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 342.13, variance = 0.428)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 385, variance = 42.8, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have opted to specify the magnitude and variance in amperes (A). It is worth noting that, despite using amperes as the input units, these keywords will still be stored in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.ammeter.magnitude.mean device.ammeter.magnitude.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-2","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the ammeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printAmmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddWattmeterManual","page":"Measurement Model","title":"Add Wattmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users can include wattmeters in either an existing measurement type or one that they create from scratch by utilizing the addWattmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6, variance = 1e-3)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.3, variance = 1e-2)\naddWattmeter!(system, device; to = \"Branch 1\", active = 0.1, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario, one wattmeter has been added to measure the active power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two wattmeters have been introduced to measure the active power flow on both sides of Branch 1 using the from and to keywords.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first and second wattmeters, we assume that the measurement values are already known, defined by the active. In contrast, for the third wattmeter, the measurement value is generated by adding white Gaussian noise with the variance to the active value. As a result, the measurement data is as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addWattmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-3","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the active and variance keywords are expected to be provided in per-unit (pu) values. However, users have the option to express these values in watts (W) if they prefer, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@power(MW, pu, pu)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddWattmeter!(system, device; bus = \"Bus 1\", active = 60, variance = 1e-1)\naddWattmeter!(system, device; from = \"Branch 1\", active = 30, variance = 1)\naddWattmeter!(system, device; to = \"Branch 1\", active = 10, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have chosen to specify the active and variance in megawatts (MW), but even though we have used megawatts as the input units, these keywords will still be stored in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.wattmeter.active.mean device.wattmeter.active.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-3","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the wattmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printWattmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddVarmeterManual","page":"Measurement Model","title":"Add Varmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To include varmeters, the same approach as described in the Add Wattmeter section can be applied, but here, we make use of the addVarmeter! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVarmeter!(system, device; bus = \"Bus 1\", reactive = 0.2, variance = 1e-3)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 0.1, variance = 1e-2)\naddVarmeter!(system, device; to = \"Branch 1\", reactive = 0.05, variance = 1e-3, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, one varmeter has been added to measure the reactive power injection at Bus 1, as indicated by the use of the bus keyword. Additionally, two varmeters have been introduced to measure the reactive power flow on both sides of Branch 1 using the from and to keywords. As a result, the following outcomes are observed:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.varmeter.reactive.mean device.varmeter.reactive.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addVarmeter! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-4","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Just as we explained for the previous device, users have the flexibility to select units different from per-units. In this case, they can opt for megavolt-ampere reactive (MVAr), as illustrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@power(pu, MVAr, pu)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddVarmeter!(system, device; bus = \"Bus 1\", reactive = 20, variance = 1e-1)\naddVarmeter!(system, device; from = \"Branch 1\", reactive = 10, variance = 1)\naddVarmeter!(system, device; to = \"Branch 1\", reactive = 5, variance = 1e-1, noise = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid will still store the values in the per-unit system:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.varmeter.reactive.mean device.varmeter.reactive.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-4","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the varmeter data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printVarmeterData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddPMUManual","page":"Measurement Model","title":"Add PMU","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the capability to incorporate PMUs into either an existing measurement type or create one from scratch by utilizing the addPmu! function, as demonstrated in the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 1.1, angle = 0.1, varianceMagnitude = 0.1)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 1.0, angle = -0.2, noise = true)\naddPmu!(system, device; to = \"Branch 1\", magnitude = 0.9, angle = 0.0, varianceAngle = 0.001)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWhile the typical understanding of a PMU encompasses a device that measures the bus voltage phasor and all branch current phasors incident to the bus, we have chosen to deconstruct this concept to offer users increased flexibility. As a result, our approach yields PMUs that measure individual phasors, each described with magnitude and angle, along with corresponding variances, all presented in the polar coordinate system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this context, one PMU has been added to measure the bus voltage phasor at Bus 1, as indicated by the use of the bus keyword. Additionally, two PMUs have been introduced to measure the branch current phasors on both sides of Branch 1 using the from and to keywords.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the first and third PMUs, we assume that the measurement values are already known, defined by the magnitude and angle keywords. However, for the second PMU, we generate the measurement value by adding white Gaussian noise with varianceMagnitude and varianceAngle to the magnitude and angle values, respectively. It is important to note that when we omit specifying variance values, we rely on their default settings, both of which are equal to 1e-5. As a result, we observe the following outcomes:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.pmu.magnitude.mean device.pmu.magnitude.variance]\n[device.pmu.angle.mean device.pmu.angle.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nWe recommend reading the documentation for the addPmu! function, where we have provided a list of the keywords that can be used.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Coordinate-Systems-and-Correlated-Measurement-Errors","page":"Measurement Model","title":"Coordinate Systems and Correlated Measurement Errors","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When users add PMUs, the incorporation of these measurements into the state estimation model is always in the rectangular coordinate system. In this scenario, the real and imaginary components of the phasor measurements become correlated, although typically these correlations are disregarded [1]. However, if users want to consider these error correlations, the keyword correlated = true is provided for support.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Further, in the AC state estimation model, users have the flexibility to integrate PMU outputs in the polar coordinate system by specifying polar = true.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For example, let us add PMUs:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.9, angle = 0, correlated = true)\naddPmu!(system, device; bus = \"Bus 2\", magnitude = 0.9, angle = 0, polar = true)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In the case of linear state estimation using PMUs only, both PMUs will be integrated into the rectangular coordinate system because the polar keyword is only related to AC state estimation. The treatment of the first PMU assumes error correlation between the real and imaginary parts. Conversely, the treatment of the second PMU assumes no correlation, as it defaults to correlated = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Next, in AC state estimation, the first PMU measurement will be integrated into the rectangular coordinate system where correlation between the real and imaginary parts exists. The second PMU will be integrated in the polar coordinate system.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nIt is noteworthy that expressing current phasor measurements in polar coordinates can lead to ill-conditioned problems due to small current magnitudes, whereas using rectangular representation can resolve this issue.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Customizing-Input-Units-for-Keywords-5","page":"Measurement Model","title":"Customizing Input Units for Keywords","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"By default, the magnitude and varianceMagnitude keywords are expected to be provided in per-unit (pu), while the angle and varianceAngle keywords are expected to be provided in radians (rad). However, users have the flexibility to express these values in different units, such as volts (V) and degrees (deg) if the PMU is set to a bus, or amperes (A) and degrees (deg) if the PMU is set to a branch. This flexibility is demonstrated in the following:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@voltage(kV, deg, V)\n@current(A, deg)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", base = 135e3)\naddBus!(system; label = \"Bus 2\", base = 135e3)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\naddPmu!(system, device; bus = \"Bus 1\", magnitude = 85.74, angle = 5.73, varianceAngle = 0.06)\naddPmu!(system, device; from = \"Branch 1\", magnitude = 427.67, angle = -11.46, noise = true)\naddPmu!(system, device; to = \"Branch 1\", magnitude = 384.91, angle = 0.0)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we have opted to specify kilovolts (kV) and degrees (deg) for the PMU located at Bus 1, and amperes (A) and degrees (deg) for the PMUs located at Branch 1. It is important to note that regardless of the units used, the values will still be stored in per-units and radians:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"[device.pmu.magnitude.mean device.pmu.magnitude.variance]\n[device.pmu.angle.mean device.pmu.angle.variance]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Print-Data-in-the-REPL-5","page":"Measurement Model","title":"Print Data in the REPL","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to print the PMU data in the REPL using any units that have been configured:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"printPmuData(system, device)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddTemplatesMeasurementManual","page":"Measurement Model","title":"Add Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The functions addVoltmeter!, addAmmeter!, addWattmeter!, addVarmeter!, and addPmu! are employed to introduce measurement devices. In cases where specific keywords are not explicitly defined, default values are automatically assigned to certain parameters.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Default-Keyword-Values","page":"Measurement Model","title":"Default Keyword Values","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When utilizing the addVoltmeter! function, the default variance is set to variance = 1e-2 per-unit, and the voltmeter's operational status is automatically assumed to be in-service, as indicated by the setting of status = 1.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, for the addAmmeter! function, the default variances are established at variance = 1e-2 per-unit, and the operational statuses are configured to status = 1. This means that if a user places an ammeter at either the from-bus or to-bus end of a branch, the default settings are identical. However, as we will explain in the following subsection, users have the flexibility to fine-tune these default values, differentiating between the two locations.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In alignment with ammeters, the addWattmeter! and addVarmeter! functions feature default variances set at variance = 1e-2 per-unit, and statuses are automatically assigned as status = 1, regardless of whether the wattmeter or varmeter is placed at the bus, the from-bus end, or the to-bus end. Users have the ability to customize these default values, making distinctions between the three positions of the measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For the addPmu! function, variances for both magnitude and angle measurements are standardized to varianceMagnitude = 1e-5 and varianceAngle = 1e-5 in per-units. Likewise, operational statuses are uniformly set to statusMagnitude = 1 and statusAngle = 1, regardless of whether the PMU is positioned on the bus, the from-bus end, or the to-bus end. Once more, users retain the option to tailor these default values to their specific needs, allowing for distinctions between these three locations of the measurement devices. Additionally, the coordinate system utilized for AC state estimation is consistently configured with polar = false, while correlation in the rectangular system is disabled with correlated = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Across all measurement devices, the method for generating measurement means is established as noise = false.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#ChangeKeywordsMeasurementManual","page":"Measurement Model","title":"Change Default Keyword Values","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In JuliaGrid, users have the flexibility to customize default values and assign personalized settings using the @voltmeter, @ammeter, @wattmeter, @varmeter, and @pmu macros. These macros create voltmeter, ammeter, wattmeter, varmeter, and pmu templates that are employed each time functions for adding measurement devices are called. Here is an example of creating these templates with tailored default values:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n@voltmeter(variance = 1e-4, noise = true)\naddVoltmeter!(system, device; label = \"Voltmeter 1\", bus = \"Bus 1\", magnitude = 1.0)\n\n@ammeter(varianceFrom = 1e-3, varianceTo = 1e-4, statusTo = 0)\naddAmmeter!(system, device; label = \"Ammeter 1\", from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; label = \"Ammeter 2\", to = \"Branch 1\", magnitude = 0.9)\n\n@wattmeter(varianceBus = 1e-3, statusFrom = 0, noise = true)\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 1\", active = 0.6)\naddWattmeter!(system, device; label = \"Wattmeter 2\", from = \"Branch 1\", active = 0.3)\naddWattmeter!(system, device; label = \"Wattmeter 3\", to = \"Branch 1\", active = 0.1)\n\n@varmeter(varianceFrom = 1e-3, varianceTo = 1e-3, statusBus = 0)\naddVarmeter!(system, device; label = \"Varmeter 1\", bus = \"Bus 1\", reactive = 0.2)\naddVarmeter!(system, device; label = \"Varmeter 2\", from = \"Branch 1\", reactive = 0.1)\naddVarmeter!(system, device; label = \"Varmeter 3\", to = \"Branch 1\", reactive = 0.05)\n\n@pmu(varianceMagnitudeBus = 1e-4, statusAngleBus = 0, varianceAngleFrom = 1e-3)\naddPmu!(system, device; label = \"PMU 1\", bus = \"Bus 1\", magnitude = 1.1, angle = -0.1)\naddPmu!(system, device; label = \"PMU 2\", from = \"Branch 1\", magnitude = 1.0, angle = -0.2)\naddPmu!(system, device; label = \"PMU 3\", to = \"Branch 1\", magnitude = 0.9, angle = 0.0)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For instance, when adding a wattmeter to the bus, the varianceBus = 1e-3 will be applied, or if it is added to the from-bus end of the branch, these wattmeters will be set as out-of-service according to statusFrom = 0.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, when adding a PMU to the bus, the variance of the bus voltage magnitude will be defined in accordance with varianceMagnitudeBus = 1e-4, while the bus voltage angle measurements will be configured as out-of-service based on the statusAngleBus = 0.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"It is important to note that changing input units will also impact the templates accordingly.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Multiple-Templates","page":"Measurement Model","title":"Multiple Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In the case of calling the macros multiple times, the provided keywords and values will be combined into a single template for the corresponding measurement device.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Reset-Templates","page":"Measurement Model","title":"Reset Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To reset the measurement device templates to their default settings, users can utilize the following macros:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"@default(voltmeter)\n@default(ammeter)\n@default(wattmeter)\n@default(varmeter)\n@default(pmu)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Additionally, users can reset all templates using the macro:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"@default(template)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#LabelsMeasurementManual","page":"Measurement Model","title":"Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"JuliaGrid necessitates a unique label for each voltmeter, ammeter, wattmeter, varmeter, or pmu. These labels are stored in order dictionaries, functioning as pairs of strings and integers. The string signifies the distinct label for the particular device, while the integer tracks the internal numbering of measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In all the previous examples, with the exception of the last one, we relied on automatic labeling by omitting the label keyword. This allowed JuliaGrid to independently assign unique labels to measurement devices. In such cases, JuliaGrid utilizes a sequential set of increasing integers for labeling the devices. The last example demonstrates the user labeling approach.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nString labels improve readability, but in larger models, the overhead from using strings can become substantial. To reduce memory usage, users can configure ordered dictionaries to accept and store integers as labels:@labels(Integers)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Integer-Based-Labeling","page":"Measurement Model","title":"Integer-Based Labeling","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us take a look at the following illustration:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n@labels(Integers)\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = 1)\naddBus!(system; label = 2)\naddBranch!(system; label = 1, from = 1, to = 2, reactance = 0.12)\n\naddVoltmeter!(system, device; label = 1, bus = 1, magnitude = 1.0)\n\naddAmmeter!(system, device; label = 1, from = 1, magnitude = 1.1)\naddAmmeter!(system, device; label = 2, to = 1, magnitude = 0.9)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we use the macro @labels to specify that labels will be stored as integers. It is essential to run this macro; otherwise, even if integers are used in subsequent functions, they will be stored as strings.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Automated-Labeling-Using-Templates","page":"Measurement Model","title":"Automated Labeling Using Templates","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can create labels using templates and include the symbol ? to insert an incremental set of integers at any position. In addition, users have the option to use the symbol ! to insert the location of the measurement device into the label. For example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\n\n@voltmeter(label = \"Voltmeter ?\")\naddVoltmeter!(system, device; bus = \"Bus 1\", magnitude = 1.0)\naddVoltmeter!(system, device; bus = \"Bus 2\", magnitude = 0.9)\n\n@ammeter(label = \"!\")\naddAmmeter!(system, device; from = \"Branch 1\", magnitude = 1.1)\naddAmmeter!(system, device; to = \"Branch 1\", magnitude = 0.9)\n\n@wattmeter(label = \"Wattmeter ?: !\")\naddWattmeter!(system, device; bus = \"Bus 1\", active = 0.6)\naddWattmeter!(system, device; from = \"Branch 1\", active = 0.3)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To illustrate, the voltmeter labels are defined with incremental integers as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.voltmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Moreover, for ammeter labels, location information is employed:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.ammeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Lastly, for wattmeters, a combination of both approaches is used:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.wattmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Retrieving-Labels","page":"Measurement Model","title":"Retrieving Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Let us explore how to retrieve stored labels. Consider the following model:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\")\naddBus!(system; label = \"Bus 2\")\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.12)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 2\", to = \"Bus 1\", reactance = 0.14)\n\naddWattmeter!(system, device; label = \"Wattmeter 2\", bus = \"Bus 2\", active = 0.6)\naddWattmeter!(system, device; label = \"Wattmeter 1\", bus = \"Bus 1\", active = 0.2)\naddWattmeter!(system, device; label = \"Wattmeter 4\", from = \"Branch 1\", active = 0.3)\naddWattmeter!(system, device; label = \"Wattmeter 3\", to = \"Branch 1\", active = 0.1)\naddWattmeter!(system, device; label = \"Wattmeter 5\", from = \"Branch 2\", active = 0.1)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To access the wattmeter labels, we can use the variable:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"device.wattmeter.label","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"If we need to obtain only labels, we can use the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(device.wattmeter.label))","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"To isolate the wattmeters positioned either at the buses or at the ends of branches (from-bus or to-bus), users can achieve this using the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label[device.wattmeter.layout.bus]\nlabel[device.wattmeter.layout.from]\nlabel[device.wattmeter.layout.to]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, when using the addWattmeter! function, the labels for the keywords bus, from, and to are stored internally as numerical values. To retrieve bus labels, we can follow this procedure:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(system.bus.label));\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.bus]]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, to obtain labels for branches, we can use the following code:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"label = collect(keys(system.branch.label));\n\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.from]]\nlabel[device.wattmeter.layout.index[device.wattmeter.layout.to]]","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This procedure is applicable to all measurement devices, including voltmeters, ammeters, varmeters, and PMUs.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"tip: Tip\nJuliaGrid offers the capability to print labels alongside various types of data. For instance, users can use the following code to print labels in combination with specific data:print(device.wattmeter.label, device.wattmeter.active.mean)","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Loading-and-Saving-Labels","page":"Measurement Model","title":"Loading and Saving Labels","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"When saving the measurements to an HDF5 file, the label type (strings or integers) will match the type chosen during system setup. Likewise, when loading data from an HDF5 file, the label type will be preserved as saved, regardless of what is set by the @labels macro.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#AddDeviceGroupsManual","page":"Measurement Model","title":"Add Multiple Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to add measurement devices with data generated from one of the AC analyses, specifically, using results obtained from either AC power flow or AC optimal power flow. To do this, users simply need to provide the AC type as an argument to one of the functions responsible for adding measurement devices:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.03, susceptance = 0.02)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.2)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\ncurrent!(system, analysis)\n\n@voltmeter(label = \"!\", noise = true)\naddVoltmeter!(system, device, analysis; variance = 1e-3)\n\n@ammeter(label = \"!\")\naddAmmeter!(system, device, analysis; varianceFrom = 1e-3, statusTo = 0, noise = true)\n\n@wattmeter(label = \"!\")\naddWattmeter!(system, device, analysis; varianceBus = 1e-3, statusFrom = 0)\n\n@varmeter(label = \"!\")\naddVarmeter!(system, device, analysis; varianceFrom = 1e-3, statusBus = 0)\n\n@pmu(label = \"!\", polar = true)\naddPmu!(system, device, analysis; varianceMagnitudeBus = 1e-3)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we incorporate voltmeters to all buses and ammeters to all branches on both ends of each branch. We set noise = true once in the template and once directly in the function, which means that measurement values are generated by adding white Gaussian noise with specified variances to perturb the values obtained from the AC power flow analysis.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"For wattmeters, varmeters, and PMUs added to all buses and branches, we rely on the default setting of noise = false to obtain measurement values that match precisely with those obtained from the AC power flow analysis. Additionally, when including PMUs in the AC state estimation model, we opt for the polar coordinate system by setting polar = true.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"note: Info\nIt is important to note that JuliaGrid follows a specific order: it first adds bus measurements, then branch measurements. For branches, it adds measurement located at the from-bus end, and immediately after, measurement at the to-bus end. This process is repeated for all in-service branches.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the option to employ an alternative method for adding groups of measurements, utilizing functions that add measurements individually. This approach may offer a more straightforward process. For example, to add wattmeters similarly to the procedure outlined above, we can employ the following:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Pᵢ = analysis.power.injection.active\nfor (label, idx) in system.bus.label\n addWattmeter!(system, device; bus = label, active = Pᵢ[idx], variance = 1e-3)\nend\n\nPᵢⱼ = analysis.power.from.active\nPⱼᵢ = analysis.power.to.active\nfor (label, idx) in system.branch.label\n addWattmeter!(system, device; from = label, active = Pᵢⱼ[idx], status = 0)\n addWattmeter!(system, device; to = label, active = Pⱼᵢ[idx])\nend\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateMeasurementDevicesManual","page":"Measurement Model","title":"Update Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"After the addition of measurement devices to the Measurement type, users possess the flexibility to modify all parameters as defined in the function that added these measurement devices.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateVoltmeterManual","page":"Measurement Model","title":"Update Voltmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users have the flexibility to modify all parameters as defined within the addVoltmeter! function. For illustration, let us continue with the example from the Add Device Groups section:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVoltmeter!(system, device; label = \"Bus 2\", magnitude = 0.9, noise = false)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we update the measurement value of the voltmeter located at Bus 2, and this measurement is now generated without the inclusion of white Gaussian noise.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateAmmeterManual","page":"Measurement Model","title":"Update Ammeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Similarly, users have the flexibility to modify all parameters defined within the addAmmeter! function. Using the same example from the Add Device Groups section, for example, we have:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateAmmeter!(system, device; label = \"From Branch 2\", magnitude = 1.2, variance = 1e-4)\nupdateAmmeter!(system, device; label = \"To Branch 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we make adjustments to the measurement and variance values of the ammeter located at Branch 2, specifically at the from-bus end. Next, we deactivate the ammeter at the same branch on the to-bus end.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateWattmeterManual","page":"Measurement Model","title":"Update Wattmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Following the same logic, users can modify all parameters defined within the addWattmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateWattmeter!(system, device; label = \"Bus 1\", active = 1.2, variance = 1e-4)\nupdateWattmeter!(system, device; label = \"To Branch 1\", variance = 1e-6)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this case, we modify the measurement and variance values for the wattmeter located at Bus 1. The wattmeter at Branch 1 on the to-bus end retains its measurement value, while only the measurement variance is adjusted.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdateVarmeterManual","page":"Measurement Model","title":"Update Varmeter","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Following the same logic, users can modify all parameters defined within the addVarmeter! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updateVarmeter!(system, device; label = \"Bus 1\", reactive = 1.2)\nupdateVarmeter!(system, device; label = \"Bus 2\", status = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this instance, we make adjustments to the measurement value of the varmeter located at Bus 1, while utilizing a previously defined variance. Furthermore, we deactivate the varmeter at Bus 2 and designate it as out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#UpdatePMUrManual","page":"Measurement Model","title":"Update PMU","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Finally, users can modify all PMU parameters defined within the addPmu! function:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"updatePmu!(system, device; label = \"Bus 1\", magnitude = 1.05, noise = true)\nupdatePmu!(system, device; label = \"From Branch 1\", varianceAngle = 1e-6, polar = false)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this example, we adjust the magnitude measurement value of the PMU located at Bus 1. Now, this measurement is generated by adding white Gaussian noise with specified variance value to perturb the magnitude value, while keeping the bus angle voltage value unchanged. For the PMU placed at Branch 1 on the from-bus end, we retain the existing measurement values and only adjust the variance of the angle measurement. Additionally, we choose to include this measurement in the rectangular coordinate system for the AC state estimation.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#MeasurementSetManual","page":"Measurement Model","title":"Measurement Set","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Once measurement devices are integrated into the Measurement type, we empower users to create measurement sets in a randomized manner. To be more precise, users can manipulate the status of devices, activating or deactivating them according to specific settings. To illustrate this feature, let us first create a measurement set using the following example:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"using JuliaGrid # hide\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\ndevice = measurement()\n\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.5, magnitude = 0.9, angle = 0.0)\naddBus!(system; label = \"Bus 2\", type = 1, reactive = 0.05, magnitude = 1.1, angle = -0.1)\naddBus!(system; label = \"Bus 3\", type = 1, active = 0.5, magnitude = 1.0, angle = -0.2)\n\n@branch(resistance = 0.03, susceptance = 0.02)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", reactance = 0.5)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", reactance = 0.1)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", reactance = 0.2)\n\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 1.2)\n\nanalysis = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\ncurrent!(system, analysis)\n\naddVoltmeter!(system, device, analysis)\naddAmmeter!(system, device, analysis)\naddPmu!(system, device, analysis)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Activating-Devices","page":"Measurement Model","title":"Activating Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"As a starting point, we create the measurement set where all devices are set to in-service mode based on default settings. In this instance, we generate the measurement set comprising 3 voltmeters, 6 ammeters, and 9 PMUs.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Subsequently, we offer users the ability to manipulate the status of in-service devices using the status! function. For example, within this set, if we wish to have only 12 out of the total 18 devices in-service while the rest are out-of-service, we can accomplish this as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; inservice = 12)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Upon executing this function, 12 devices will be randomly selected to be in-service, while the remaining 6 will be set to out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can fine-tune the manipulation of specific measurements. Let us say we want to activate only 2 ammeters while deactivating the remaining ammeters:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusAmmeter!(system, device; inservice = 2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"This action will result in 2 ammeters being in-service and 4 being out-of-service.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Users also have the option to further refine these actions by specifying devices at particular locations within the power system. For instance, we can enable 3 PMUs at buses to measure bus voltage phasors while deactivating all PMUs at branches that measure current phasors:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"statusPmu!(system, device; inserviceBus = 3, inserviceFrom = 0, inserviceTo = 0)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"The outcome will be that 3 PMUs are set to in-service at buses for voltage phasor measurements, while all PMUs at branches measuring current phasors will be in out-of-service mode.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Deactivating-Devices","page":"Measurement Model","title":"Deactivating Devices","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Likewise, we empower users to specify the number of devices to be set as out-of-service rather than defining the number of in-service devices. For instance, if the intention is to deactivate just 2 devices from the total measurement set, it can be achieved as follows:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; outservice = 2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"In this scenario 2 devices will be randomly deactivated, while the rest will remain in in-service status. Similar to the previous approach, users can apply this to specific devices or employ fine-tuning as needed.","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"","category":"page"},{"location":"manual/measurementModel/#Activating-Devices-Using-Redundancy","page":"Measurement Model","title":"Activating Devices Using Redundancy","text":"","category":"section"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Furthermore, users can take advantage of redundancy, which represents the ratio between measurement devices and state variables. For example, if we wish to have the number of measurement devices be 1.2 times greater than the number of state variables, we can utilize the following command:","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"status!(system, device; redundancy = 1.2)\nnothing # hide","category":"page"},{"location":"manual/measurementModel/","page":"Measurement Model","title":"Measurement Model","text":"Considering that the number of state variables is 5 (excluding the voltage angle related to the slack bus), using a redundancy value of 1.2 will result in 6 devices being set to in-service, while the remainder will be deactivated. As before, users can target specific devices or adjust settings as needed.","category":"page"},{"location":"background/bibliography/#Bibliography","page":"Bibliography","title":"Bibliography","text":"","category":"section"},{"location":"background/bibliography/","page":"Bibliography","title":"Bibliography","text":"A. Gomez-Exposito, A. Abur, P. Rousseaux, A. de la Villa Jaen and C. Gomez-Quiles. On the use of PMUs in power system state estimation. In: 17th power system computation conference (2011).\n\n\n\nG. N. Korres. Observability analysis based on Echelon form of a reduced dimensional Jacobian matrix. IEEE Transactions on Power Systems 26, 2572–2573 (2011).\n\n\n\nM. Zhou, V. A. Centeno, J. S. Thorp and A. G. Phadke. An alternative for including phasor measurements in state estimators. IEEE transactions on power systems 21, 1930–1937 (2006).\n\n\n\nG. Korres and N. Manousakis. State estimation and observability analysis for phasor measurement unit measured systems. IET generation, transmission & distribution 6, 902–913 (2012).\n\n\n\nA. Abur and A. G. Exposito. Power system state estimation: theory and implementation (CRC press, 2004).\n\n\n\nG. Andersson. Power system analysis. EEH-Power Systems Laboratory, ETH Zurich, Lecture Notes, 227–0526 (2012).\n\n\n\nJ. J. Grainger and W. D. Stevenson. Power system analysis (McGraw-Hill, 1994).\n\n\n\nR. D. Zimmerman and C. E. Murillo-Sánchez. Matpower 6.0 users manual. Power Systems Engineering Research Center 9 (2016).\n\n\n\nA. J. Wood, B. F. Wollenberg and G. B. Sheblé. Power generation, operation, and control (John Wiley & Sons, 2013).\n\n\n\nR. A. Van Amerongen. A general-purpose version of the fast decoupled load flow. IEEE Transactions on Power Systems 4, 760–770 (1989).\n\n\n\nD. P. Chassin, P. R. Armstrong, D. G. Chavarrı́a-Miranda and R. T. Guttromson. Gauss-Seidel accelerated: implementing flow solvers on field programmable gate arrays. In: 2006 IEEE Power Engineering Society General Meeting (IEEE, 2006); p. 5–pp.\n\n\n\nF. C. Schweppe and D. B. Rom. Power system static-state estimation, Part II: Approximate model. IEEE Transactions on Power Apparatus and Systems, 125–130 (1970).\n\n\n\nA. Monticelli. State estimation in electric power systems: a generalized approach (Springer Science & Business Media, 2012).\n\n\n\nA. G. Phadke and J. S. Thorp. Synchronized phasor measurements and their applications. Vol. 1 no. 2017 (Springer, 2008).\n\n\n\nD. Barber. Bayesian reasoning and machine learning (Cambridge University Press, 2012).\n\n\n\nI. ISO. and B. OIML. Guide to the Expression of Uncertainty in Measurement (Aenor, 1993).\n\n\n\nY. Weng, Q. Li, R. Negi and M. Ilić. Semidefinite programming for power system state estimation. In: 2012 IEEE Power and Energy Society General Meeting (IEEE, 2012); pp. 1–8.\n\n\n\nP. C. Hansen, V. Pereyra and G. Scherer. Least squares data fitting with applications (JHU Press, 2013).\n\n\n\nG. N. Korres. A distributed multiarea state estimation. IEEE Transactions on Power Systems 26, 73–84 (2010).\n\n\n\nM. Cosovic, M. Delalic, D. Raca and D. Vukobratovic. Observability analysis for large-scale power systems using factor graphs. IEEE Transactions on Power Systems 36, 4791–4799 (2021).\n\n\n\nH. Horisberger. Observability analysis for power systems with measurement deficiencies. IFAC Proceedings Volumes 18, 51–58 (1985).\n\n\n\nN. M. Manousakis and G. N. Korres. Observability analysis for power systems including conventional and phasor measurements. IET Conference Proceedings, 158-158(1) (2010).\n\n\n\nB. Gou. Optimal placement of PMUs by integer linear programming. IEEE Transactions on power systems 23, 1525–1526 (2008).\n\n\n\nB. Xu and A. Abur. Observability analysis and measurement placement for systems with PMUs. In: IEEE PES Power Systems Conference and Exposition, 2004. (IEEE, 2004); pp. 943–946.\n\n\n\n","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowManual","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid utilizes the JuMP package to construct optimal power flow models, allowing users to manipulate these models using the standard functions provided by JuMP. As a result, JuliaGrid supports popular solvers mentioned in the JuMP documentation to solve the optimization problem.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To perform the AC optimal power flow, we first need to have the PowerSystem type that has been created with the AC model. After that, create the ACOptimalPowerFlow type to establish the AC optimal power flow framework using the function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"acOptimalPowerFlow.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To solve the AC optimal power flow problem and acquire bus voltage magnitudes and angles, and generator active and reactive power outputs, make use of the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"solve!.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the AC optimal power flow solution, JuliaGrid offers post-processing analysis functions to calculate powers and currents associated with buses and branches:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!,\ncurrent!.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, specialized functions are available for calculating specific types of powers or currents for individual buses, branches, or generators.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowModelManual","page":"AC Optimal Power Flow","title":"Optimal Power Flow Model","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To set up the AC optimal power flow, we begin by creating the model. To illustrate this, consider the following:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid # hide\nusing JuMP, Ipopt\n@default(unit) # hide\n@default(template) # hide\n\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.95, maxMagnitude = 1.05)\naddBus!(system; label = \"Bus 1\", type = 3, active = 0.1, angle = -0.1)\naddBus!(system; label = \"Bus 2\", reactive = 0.01, magnitude = 1.1)\n\n@branch(minDiffAngle = -pi, maxDiffAngle = pi, reactance = 0.5, type = 2)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", maxFromBus = 0.15)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1, status = 0)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 0.4, reactive = 0.2)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, reactive = 0.1)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [800.0; 200.0; 80.0])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\ncost!(system; label = \"Generator 1\", reactive = 2, polynomial = [2.0])\ncost!(system; label = \"Generator 2\", reactive = 1, piecewise = [2.0 4.0; 6.0 8.0])\n\nacModel!(system)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, the acOptimalPowerFlow function is utilized to formulate the AC optimal power flow problem:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimizationVariablesManual","page":"AC Optimal Power Flow","title":"Optimization Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the AC optimal power flow model, the active and reactive power outputs of the generators are expressed as nonlinear functions of the bus voltage magnitudes and angles. As a result, the variables in this model include the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.all_variables(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is important to note that this is not a comprehensive set of optimization variables. When the cost function is defined as a linear piecewise function comprising multiple segments, as illustrated in the case of the active power output cost for Generator 2, JuliaGrid automatically generates helper optimization variables named actwise and reactwise, and formulates a set of linear constraints to effectively address these cost functions. For the sake of simplicity, we initially assume that Generator 2 is out-of-service. Consequently, the helper variable is not included in the set of optimization variables. However, as we progress through this manual, we will activate the generator, introducing the helper variable and additional constraints to the optimization model.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is worth emphasizing that in instances where a linear piecewise cost function consists of only a single segment, as demonstrated by the reactive power output cost of Generator 2, the function is modeled as a standard linear function, obviating the need for additional helper optimization variables.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Please be aware that JuliaGrid maintains references to all variables, which are categorized into six fields:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.variable))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Variable-Names","page":"AC Optimal Power Flow","title":"Variable Names","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the option to define custom variable names for printing and writing equations, which can help present them in a more compact form. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis = acOptimalPowerFlow(system, Ipopt.Optimizer; magnitude = \"V\", angle = \"θ\")\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-Variables","page":"AC Optimal Power Flow","title":"Add Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The user has the ability to easily add new variables to the defined AC optimal power flow model by using the @variable macro from the JuMP package:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.@variable(analysis.method.jump, newVariable)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can verify that the new variable is included in the defined model by using the function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Delete-Variables","page":"AC Optimal Power Flow","title":"Delete Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The variable can be deleted, but this operation is only applicable if the objective function is either affine or quadratic. To achieve this, we can utilize the delete function provided by the JuMP, as demonstrated below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After deletion, the variable is no longer part of the model:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.is_valid(analysis.method.jump, newVariable)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#DCConstraintFunctionsManual","page":"AC Optimal Power Flow","title":"Constraint Functions","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid keeps track of all the references to internally formed constraints in the constraint field of the ACOptimalPowerFlow type. These constraints are divided into six fields:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"fieldnames(typeof(analysis.method.constraint))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nWe suggest that readers refer to the tutorial on AC Optimal Power Flow for insights into the implementation.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Slack-Bus-Constraint","page":"AC Optimal Power Flow","title":"Slack Bus Constraint","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The slack field contains a reference to the equality constraint associated with the fixed bus voltage angle value of the slack bus. This constraint is set within the addBus! function using the angle keyword:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the flexibility to modify this constraint by changing which bus serves as the slack bus and by adjusting the value of the bus angle. This can be achieved using the updateBus! function, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", type = 1)\nupdateBus!(system, analysis; label = \"Bus 2\", type = 3, angle = -0.2)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated slack constraint can be inspected as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.slack.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Bus-Power-Balance-Constraints","page":"AC Optimal Power Flow","title":"Bus Power Balance Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The balance field contains references to the equality constraints associated with the active and reactive power balance equations defined for each bus. These constraints ensure that the total active and reactive power injected by the generators matches the total active and reactive power demanded at each bus.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constant term in the active power balance equations is determined by the active keyword within the addBus! function, which defines the active power demanded at the bus. We can access the references to the active power balance constraints using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the constant term in the reactive power balance equations is determined by the reactive keyword within the addBus! function, which defines the reactive power demanded at the bus. We can access the references to the reactive power balance constraints using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"During the execution of functions that add or update power system components, these constraints are automatically adjusted to reflect the current configuration of the power system, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 2\", active = 0.5)\nupdateBranch!(system, analysis; label = \"Branch 1\", reactance = 0.25)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The updated set of active power balance constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.balance.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Bus-Voltage-Constraints","page":"AC Optimal Power Flow","title":"Bus Voltage Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The voltage field contains references to the inequality constraints associated with the voltage magnitude and voltage angle difference limits. These constraints ensure that the bus voltage magnitudes and the angle differences between the from-bus and to-bus ends of each branch are within specified limits.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The minimum and maximum bus voltage magnitude limits are set using the minMagnitude and maxMagnitude keywords within the addBus! function. The constraints associated with these limits can be accessed using:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.voltage.magnitude)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The minimum and maximum voltage angle difference limits between the from-bus and to-bus ends of each branch are set using the minDiffAngle and maxDiffAngle keywords within the addBranch! function. The constraints associated with these limits can be accessed using the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nPlease note that if the limit constraints are set to minDiffAngle = -2π and maxDiffAngle = 2π for the corresponding branch, JuliGrid will omit the corresponding inequality constraint.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, by employing the updateBus! and updateBranch! functions, the user has the ability to modify these specific constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBus!(system, analysis; label = \"Bus 1\", minMagnitude = 1.0, maxMagnitude = 1.0)\nupdateBranch!(system, analysis; label = \"Branch 1\", minDiffAngle = -1.7, maxDiffAngle = 1.7)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated set of constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.method.constraint.voltage.magnitude)\nprint(system.branch.label, analysis.method.constraint.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACBranchFlowConstraintsManual","page":"AC Optimal Power Flow","title":"Branch Flow Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The flow field contains references to the inequality constraints associated with the apparent power flow, active power flow, or current flow magnitude limits at the from-bus and to-bus ends of each branch. The type to which one of the constraints will be applied is defined according to the type keyword within the addBranch! function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"type = 1 for the apparent power flow,\ntype = 2 for the active power flow,\ntype = 3 for the current flow magnitude.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"These limits are specified using the minFromBus, maxFromBus, minToBus and maxToBus keywords within the addBranch! function. By default, these limit keywords are associated with apparent power (type = 1).","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"However, in the example, we configured it to use active power flow by setting type = 2. To access the flow constraints of branches at the from-bus end, we can utilize the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.from)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nIf the branch flow limits are set to minFromBus = 0.0 and maxFromBus = 0.0 for the corresponding branch, JuliGrid will omit the corresponding inequality constraint at the from-bus end of the branch. The same applies to the to-bus end if minToBus = 0.0 and maxToBus = 0.0 are set.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Additionally, by employing the updateBranch! function, we have the ability to modify these specific constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateBranch!(system, analysis; label = \"Branch 1\", minFromBus = -0.15, maxToBus = 0.15)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The updated set of flow constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.flow.from)\nprint(system.branch.label, analysis.method.constraint.flow.to)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"tip: Tip\nIn typical scenarios, minFromBus is equal to minToBus, and maxFromBus is equal to maxToBus. However, we allow these values to be defined separately for greater flexibility, enabling, among other things, the option to apply constraints on only one side of the branch.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Generator-Power-Capability-Constraints","page":"AC Optimal Power Flow","title":"Generator Power Capability Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The capability field contains references to the inequality constraints associated with the minimum and maximum active and reactive power outputs of the generators.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The constraints associated with the minimum and maximum active power output limits of the generators are defined using the minActive and maxActive keywords within the addGenerator! function. To access the constraints associated with these limits, we can use the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, the constraints associated with the minimum and maximum reactive power output limits of the generators are specified using the minReactive and maxReactive keywords within the addGenerator! function. To access these constraints, we can use the following code snippet:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As demonstrated, the active and reactive power outputs of Generator 1 and Generator 2 are currently fixed at zero due to previous actions that set these generators out-of-service. However, we can modify these specific constraints by utilizing the updateGenerator! function, as shown below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 1\", status = 1)\nupdateGenerator!(system, analysis; label = \"Generator 2\", status = 1, minActive = 0.1)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Subsequently, the updated set of constraints can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.capability.active)\nprint(system.generator.label, analysis.method.constraint.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nThis representation may not fully capture the generator's power output behavior due to the tradeoff between active and reactive power outputs. JuliaGrid can incorporate this tradeoff in its optimization model. For more information, see the tutorial on Power Capability Constraints.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Power-Piecewise-Constraints","page":"AC Optimal Power Flow","title":"Power Piecewise Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the context of cost modeling, the piecewise field acts as a reference to the inequality constraints associated with linear piecewise cost functions. These constraints are established using the cost! function, with active = 1 or reactive = 1 specified when working with linear piecewise cost functions that consist of multiple segments.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In our example, only the active power cost of Generator 2 is modeled as a linear piecewise function with two segments, and JuliaGrid takes care of setting up the appropriate inequality constraints for each segment:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.constraint.piecewise.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"It is worth noting that these constraints can also be automatically updated using the cost! function. Readers can find more details in the section discussing the objective function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As mentioned at the beginning, linear piecewise cost functions with multiple segments will also introduce helper variables that are added to the objective function. In this specific example, the helper variable is:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.variable.actwise[2]","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-Constraints","page":"AC Optimal Power Flow","title":"Add Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can effortlessly introduce additional constraints into the defined AC optimal power flow model by utilizing the addBranch! or addGenerator! functions. Specifically, if a user wishes to include a new branch or generator in an already defined PowerSystem and ACOptimalPowerFlow type:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"addBranch!(system, analysis; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 2\", reactance = 1)\naddGenerator!(system, analysis; label = \"Generator 3\", bus = \"Bus 2\", active = 2, status = 1)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"This will affect all constraints related to branches and generators, but it will also update balance constraints to configure the optimization model to match the current state of the power system. For example, we can observe the following updated constraints:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.branch.label, analysis.method.constraint.voltage.angle)\nprint(system.generator.label, analysis.method.constraint.capability.active)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Add-User-Defined-Constraints","page":"AC Optimal Power Flow","title":"Add User-Defined Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users also have the option to include their custom constraints within the established AC optimal power flow model by employing the @constraint macro. For example, the addition of a new constraint can be achieved as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.@constraint(analysis.method.jump, 0.0 <= analysis.method.variable.active[3] <= 0.3)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Delete-Constraints","page":"AC Optimal Power Flow","title":"Delete Constraints","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To delete a constraint, users can make use of the delete function from the JuMP package. When handling constraints that have been internally created, users can refer to the constraint references stored in the constraint field of the ACOptimalPowerFlow type.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For example, if the intention is to eliminate constraints related to the capability of Generator 3, we can use:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.delete(analysis.method.jump, analysis.method.constraint.capability.active[3])\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nIn the event that a user deletes a constraint and subsequently executes a function that updates bus, branch, or generator parameters, and if the deleted constraint is affected by these functions, JuliaGrid will automatically reinstate that constraint. Users should exercise caution when deleting constraints, as this action is considered potentially harmful since it operates independently of power system data.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACObjectiveFunctionManual","page":"AC Optimal Power Flow","title":"Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The objective function of the AC optimal power flow is formulated using polynomial and linear piecewise cost functions associated with the generators, defined using the cost! functions.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the provided example, the objective function to be minimized in order to obtain optimal values for the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles, is as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuliaGrid also stores the objective function in a separate variable, which can be accessed by referring to the variable analysis.objective. In this variable, the objective function is organized in a way that separates the quadratic and nonlinear components of the objective function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Update-Objective-Function","page":"AC Optimal Power Flow","title":"Update Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By utilizing the cost! functions, users have the flexibility to modify the objective function by adjusting polynomial or linear piecewise coefficients or by changing the type of polynomial or linear piecewise function employed. For example, consider Generator 1, which employs a quadratic polynomial cost function for active power. We can redefine the cost function for this generator as a cubic polynomial and thereby define a nonlinear objective function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"cost!(system, analysis; label = \"Generator 1\", active = 2, polynomial = [631; 257; 40; 5.0])\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"This leads to an updated objective function, which can be examined as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#User-Defined-Objective-Function","page":"AC Optimal Power Flow","title":"User-Defined Objective Function","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can modify the objective function using the set_objective_function function from the JuMP package. This operation is considered destructive because it is independent of power system data; however, in certain scenarios, it may be more straightforward than using the cost! function for updates. Moreover, using this methodology, users can combine a defined function with a newly defined expression.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this context, we can utilize the saved objective function within the objective field of the ACOptimalPowerFlow type. For example, we can easily eliminate nonlinear parts and alter the quadratic component of the objective:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"expr = 5.0 * analysis.method.variable.active[1] * analysis.method.variable.active[1]\nJuMP.set_objective_function(analysis.method.jump, analysis.method.objective.quadratic - expr)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can now observe the updated objective function as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_function(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACSetupPrimalStartingValuesManual","page":"AC Optimal Power Flow","title":"Setup Starting Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In JuliaGrid, the assignment of starting primal and dual values for optimization variables and constraints takes place when the solve! function is executed.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Starting-Primal-Values","page":"AC Optimal Power Flow","title":"Starting Primal Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Starting primal values are determined based on the generator and voltage fields within the ACOptimalPowerFlow type. By default, these values are initially established using the active and reactive power outputs of the generators and the initial bus voltage magnitudes and angles:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"generator = analysis.power.generator;\nprint(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users have the flexibility to adjust these values according to their specifications, which will then be used as the starting primal values when executing the solve! function.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Using-AC-Power-Flow","page":"AC Optimal Power Flow","title":"Using AC Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In this perspective, users have the capability to conduct the AC power flow analysis and leverage the resulting solution to configure starting primal values. Here is an illustration of how this can be achieved:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"flow = newtonRaphson(system)\nfor iteration = 1:100\n stopping = mismatch!(system, flow)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, flow)\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the solution, we can calculate the active and reactive power outputs of the generators and utilize the bus voltage magnitudes and angles to set the starting values. In this case, the generator and voltage fields of the ACOptimalPowerFlow type can be employed to store the new starting values:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"for (key, idx) in system.generator.label\n active, reactive = generatorPower(system, flow; label = key)\n analysis.power.generator.active[idx] = active\n analysis.power.generator.reactive[idx] = reactive\nend\n\nfor i = 1:system.bus.number\n analysis.voltage.magnitude[i] = flow.voltage.magnitude[i]\n analysis.voltage.angle[i] = flow.voltage.angle[i]\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Starting-Dual-Values","page":"AC Optimal Power Flow","title":"Starting Dual Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Dual variables, often referred to as Lagrange multipliers or Kuhn-Tucker multipliers, represent the shadow prices or marginal costs associated with constraints. The assignment of initial dual values occurs when the solve! function is executed. Initially, the starting dual values are unknown, but users can access and manually set them. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.dual.balance.active[1] = 0.4\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerFlowSolutionManual","page":"AC Optimal Power Flow","title":"Optimal Power Flow Solution","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To establish the AC optimal power flow problem, we can utilize the acOptimalPowerFlow function. After setting up the problem, we can use the solve! function to compute the optimal values for the active and reactive power outputs of the generators and the bus voltage magnitudes angles. Also, to turn off the solver output within the REPL, we use the set_silent function before calling solve! function. Here is an example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.set_silent(analysis.method.jump)\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"By executing this function, we will obtain the solution with the optimal values for the active and reactive power outputs of the generators, as well as the bus voltage magnitudes and angles.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"generator = analysis.power.generator;\nprint(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Objective-Value","page":"AC Optimal Power Flow","title":"Objective Value","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To obtain the objective value of the optimal power flow solution, we can use the objective_value function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"JuMP.objective_value(analysis.method.jump)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Dual-Variables","page":"AC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The values of the dual variables are stored in the dual field of the ACOptimalPowerFlow type. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"analysis.method.dual.balance.active[1]","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Print-Results-in-the-REPL","page":"AC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can utilize the functions printBusData and printGeneratorData to display results. Additionally, the functions listed in the Print Constraint Data section allow users to print constraint data related to buses, branches, or generators in the desired units. For example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"@power(MW, MVAr, pu)\nshow = Dict(\"Active Power Balance\" => false)\nprintBusConstraint(system, analysis; show)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, users can easily customize the print results for specific constraint, for example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"printBusConstraint(system, analysis; label = \"Bus 1\", header = true)\nprintBusConstraint(system, analysis; label = \"Bus 2\", footer = true)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Save-Results-to-a-File","page":"AC Optimal Power Flow","title":"Save Results to a File","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can also redirect print output to a file. For example, data can be saved in a text file as follows:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"open(\"bus.txt\", \"w\") do file\n printBusConstraint(system, analysis, file)\nend","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Save-Results-to-a-CSV-File","page":"AC Optimal Power Flow","title":"Save Results to a CSV File","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using CSV\n\nio = IOBuffer()\nprintBusConstraint(system, analysis, io; style = false)\nCSV.write(\"constraint.csv\", CSV.File(take!(io); delim = \"|\"))","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Primal-and-Dual-Warm-Start","page":"AC Optimal Power Flow","title":"Primal and Dual Warm Start","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Utilizing the ACOptimalPowerFlow type and proceeding directly to the solver offers the advantage of a \"warm start\". In this scenario, the starting primal and dual values for the subsequent solving step correspond to the solution obtained from the previous step.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Primal-Variables","page":"AC Optimal Power Flow","title":"Primal Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"In the previous example, the following solution was obtained, representing the values of the primal variables:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Dual-Variables-2","page":"AC Optimal Power Flow","title":"Dual Variables","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We also obtained all dual values. Here, we list only the dual variables for one type of constraint as an example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, analysis.method.dual.capability.reactive)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Modify-Optimal-Power-Flow","page":"AC Optimal Power Flow","title":"Modify Optimal Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Now, let us introduce changes to the power system from the previous example:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"updateGenerator!(system, analysis; label = \"Generator 2\", maxActive = 0.08)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Next, we want to solve this modified optimal power flow problem. If we use solve! at this point, the primal and dual starting values will be set to the previously obtained values:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"solve!(system, analysis)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"As a result, we obtain a new solution:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.generator.label, generator.active, generator.reactive)\nprint(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Reset-Primal-and-Dual-Values","page":"AC Optimal Power Flow","title":"Reset Primal and Dual Values","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users retain the flexibility to reset initial primal values to their default configurations at any juncture. This can be accomplished by utilizing the active and reactive power outputs of the generators and the initial bus voltage magnitudes and angles extracted from the PowerSystem type, employing the startingPrimal! function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"startingPrimal!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The primal starting values will now be identical to those that would be obtained if the acOptimalPowerFlow function were executed after all the updates have been applied.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Using the startingDual! function, users can clear all dual variable values, resetting them to their default state:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"startingDual!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#ACOptimalPowerCurrentAnalysisManual","page":"AC Optimal Power Flow","title":"Power and Current Analysis","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"After obtaining the solution from the AC optimal power flow, we can calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, let us consider the power system for which we obtained the AC optimal power flow solution:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"using JuliaGrid, JuMP # hide\nusing Ipopt\n\n@default(unit) # hide\n@default(template) # hide\nsystem = powerSystem()\n\n@bus(minMagnitude = 0.9, maxMagnitude = 1.1)\naddBus!(system; label = \"Bus 1\", type = 3, magnitude = 1.05, angle = 0.17)\naddBus!(system; label = \"Bus 2\", active = 0.1, reactive = 0.01, conductance = 0.04)\naddBus!(system; label = \"Bus 3\", active = 0.05, reactive = 0.02)\n\n@branch(resistance = 0.5, reactance = 1.0, conductance = 1e-4, susceptance = 0.01)\naddBranch!(system; label = \"Branch 1\", from = \"Bus 1\", to = \"Bus 2\", maxFromBus = 0.15)\naddBranch!(system; label = \"Branch 2\", from = \"Bus 1\", to = \"Bus 3\", maxFromBus = 0.10)\naddBranch!(system; label = \"Branch 3\", from = \"Bus 2\", to = \"Bus 3\", maxFromBus = 0.25)\n\n@generator(maxActive = 0.5, minReactive = -0.1, maxReactive = 0.1)\naddGenerator!(system; label = \"Generator 1\", bus = \"Bus 1\", active = 3.2, reactive = 0.5)\naddGenerator!(system; label = \"Generator 2\", bus = \"Bus 2\", active = 0.2, reactive = 0.1)\n\ncost!(system; label = \"Generator 1\", active = 2, polynomial = [1100.2; 500; 80])\ncost!(system; label = \"Generator 2\", active = 1, piecewise = [10.8 12.3; 14.7 16.8; 18 18.1])\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nJuMP.set_silent(analysis.method.jump) # hide\nsolve!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can now utilize the following functions to calculate powers and currents:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"power!(system, analysis)\ncurrent!(system, analysis)\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"For instance, if we want to show the active power injections and the from-bus current magnitudes, we can employ:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"print(system.bus.label, analysis.power.injection.active)\nprint(system.branch.label, analysis.current.from.magnitude)","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"note: Info\nTo better understand the powers and current associated with buses and branches that are calculated by the power! and current! functions, we suggest referring to the tutorials on AC Optimal Power Flow.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Print-Results-in-the-REPL-2","page":"AC Optimal Power Flow","title":"Print Results in the REPL","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Users can utilize any of the print functions outlined in the Print Power System Data or Print Power System Summary. For example, to create a bus data with the desired units, users can use the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"@voltage(pu, deg, V)\n@power(MW, MVAr, pu)\nshow = Dict(\"Power Generation\" => false, \"Current Injection\" => false)\nprintBusData(system, analysis; show)\n@default(unit) # hide\nnothing # hide","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Injection","page":"AC Optimal Power Flow","title":"Active and Reactive Power Injection","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = injectionPower(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Injection-from-Generators","page":"AC Optimal Power Flow","title":"Active and Reactive Power Injection from Generators","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power injection from the generators at a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = supplyPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Shunt-Element","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Shunt Element","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power associated with shunt element at a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = shuntPower(system, analysis; label = \"Bus 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-Flow","page":"AC Optimal Power Flow","title":"Active and Reactive Power Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Similarly, we can compute the active and reactive power flow at both the from-bus and to-bus ends of the specific branch by utilizing the provided functions below:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = fromPower(system, analysis; label = \"Branch 2\")\nactive, reactive = toPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Charging-Admittances","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Charging Admittances","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the total active and reactive power linked with branch charging admittances of the particular branch, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = chargingPower(system, analysis; label = \"Branch 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances injected reactive powers into the power system due to their capacitive nature, as denoted by a negative sign.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Active-and-Reactive-Power-at-Series-Impedance","page":"AC Optimal Power Flow","title":"Active and Reactive Power at Series Impedance","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the active and reactive power across the series impedance of the branch, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"active, reactive = seriesPower(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Injection","page":"AC Optimal Power Flow","title":"Current Injection","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the current injection associated with a specific bus, the function can be used:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = injectionCurrent(system, analysis; label = \"Bus 1\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Flow","page":"AC Optimal Power Flow","title":"Current Flow","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"We can compute the current flow at both the from-bus and to-bus ends of the specific branch by using:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = fromCurrent(system, analysis; label = \"Branch 2\")\nmagnitude, angle = toCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"","category":"page"},{"location":"manual/acOptimalPowerFlow/#Current-Through-Series-Impedance","page":"AC Optimal Power Flow","title":"Current Through Series Impedance","text":"","category":"section"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, we can use the following function:","category":"page"},{"location":"manual/acOptimalPowerFlow/","page":"AC Optimal Power Flow","title":"AC Optimal Power Flow","text":"magnitude, angle = seriesCurrent(system, analysis; label = \"Branch 2\")","category":"page"},{"location":"api/setupPrint/#setupPrintAPI","page":"Setup and Print","title":"Setup and Print","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"For further information on this topic, please see the Power System Model or Measurement Model sections of the Manual. Please note that when using macros, they modify variables within the current scope. Print functions can be used to print results to the REPL, or users can redirect the output to print results to a text file, for example.","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"To load power system model API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"using JuliaGrid","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Base-Units","page":"Setup and Print","title":"Base Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@base","category":"page"},{"location":"api/setupPrint/#Input-Units","page":"Setup and Print","title":"Input Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@power\n@voltage\n@current\n@parameter","category":"page"},{"location":"api/setupPrint/#Label-Types","page":"Setup and Print","title":"Label Types","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@labels","category":"page"},{"location":"api/setupPrint/#Default-Settings","page":"Setup and Print","title":"Default Settings","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@default","category":"page"},{"location":"api/setupPrint/#Print-Power-System-Data","page":"Setup and Print","title":"Print Power System Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusData\nprintBranchData\nprintGeneratorData","category":"page"},{"location":"api/setupPrint/#Print-Power-System-Summary","page":"Setup and Print","title":"Print Power System Summary","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusSummary\nprintBranchSummary\nprintGeneratorSummary","category":"page"},{"location":"api/setupPrint/#Print-Measurement-Data","page":"Setup and Print","title":"Print Measurement Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printVoltmeterData\nprintAmmeterData\nprintWattmeterData\nprintVarmeterData\nprintPmuData","category":"page"},{"location":"api/setupPrint/#Print-Constraint-Data","page":"Setup and Print","title":"Print Constraint Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusConstraint\nprintBranchConstraint\nprintGeneratorConstraint","category":"page"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Base-Units-2","page":"Setup and Print","title":"Base Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@base","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@base","page":"Setup and Print","title":"JuliaGrid.@base","text":"@base(system::PowerSystem, power, voltage)\n\nBy default, the units for base power and base voltages are set to volt-ampere (VA) and volt (V), but you can modify the prefixes using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of power (VA) or unit of voltage (V). Keep in mind that the macro must be used after creating the composite type PowerSystem.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n@base(system, MVA, kV)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Input-Units-2","page":"Setup and Print","title":"Input Units","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@power\n@voltage\n@current\n@parameter","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@power","page":"Setup and Print","title":"JuliaGrid.@power","text":"@power(active, reactive, apparent)\n\nJuliaGrid stores all data related with powers in per-units, and these cannot be altered. However, the power units of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of active power (W), reactive power (VAr), or apparent power (VA). Also, it is a possible to combine SI units with/without prefixes with per-units (pu).\n\nChanging the unit of active power is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: active, conductance;\naddBranch!, updateBranch!, @branch: if type = 2: minFromBus, maxFromBus, minToBus, maxToBus;\naddGenerator!, updateGenerator!, @generator: active, minActive, maxActive, lowActive, upActive, loadFollowing, reserve10min, reserve30min;\ncost!: if active: piecewise, polynomial;\naddWattmeter!, updateWattmeter!: active, variance;\n@wattmeter: , varianceBus, varianceFrom, varianceTo.\n\nChanging the unit of reactive power unit is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: reactive, susceptance;\naddGenerator!, updateGenerator!, @generator: reactive, minReactive, maxReactive, minLowReactive, maxLowReactive, minUpReactive, maxUpReactive, reactiveRamp;\ncost!: if reactive: piecewise, polynomial;\naddVarmeter!, updateVarmeter!: reactive, variance;\n@varmeter: varianceBus, varianceFrom, varianceTo.\n\nChanging the unit of apparent power unit is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: if type = 1: minFromBus, maxFromBus, minToBus, maxToBus.\n\nExample\n\n@power(MW, kVAr, VA)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@voltage","page":"Setup and Print","title":"JuliaGrid.@voltage","text":"@voltage(magnitude, angle, base)\n\nJuliaGrid stores all data related with voltages in per-units and radians, and these cannot be altered. However, the voltage magnitude and angle units of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nThe prefixes must adhere to the SI prefixes and should be specified along with the unit of voltage, either magnitude (V) or base (V). Alternatively, the unit of voltage magnitude can be expressed in per-unit (pu). The unit of voltage angle should be in radians (rad) or degrees (deg).\n\nChanging the unit of voltage magnitude is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: magnitude, minMagnitude, maxMagnitude;\naddGenerator!, updateGenerator!, @generator: magnitude;\naddVoltmeter!, updateVoltmeter!, @voltmeter: magnitude, variance;\naddPmu!, updatePmu!: if bus: magnitude, varianceMagnitude;\n@pmu: varianceMagnitudeBus.\n\nChanging the unit of voltage angle is reflected in the following quantities:\n\naddBus!, updateBus!, @bus: angle;\naddBranch!, updateBranch!, @branch: shiftAngle, minDiffAngle, maxDiffAngle;\naddPmu!, updatePmu!: if bus: angle, varianceAngle;\n@pmu: varianceAngleBus.\n\nChanging the unit prefix of voltage base is reflected in the following quantity:\n\naddBus!, updateBus!, @bus: base.\n\nExample\n\n@voltage(pu, deg, kV)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@current","page":"Setup and Print","title":"JuliaGrid.@current","text":"@current(magnitude, angle)\n\nJuliaGrid stores all data related with currents in per-units and radians, and these cannot be altered. However, the current magnitude and angle units of the built-in functions used to add or modified measurement devices can be modified using the macro.\n\nThe prefixes must adhere to the SI prefixes and should be specified along with the unit of current magnitude (V). Alternatively, the unit of current magnitude can be expressed in per-unit (pu). The unit of current angle should be in radians (rad) or degrees (deg).\n\nChanging the unit of current magnitude is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: if type = 3: minFromBus, maxFromBus, minToBus, maxToBus.\naddAmmeter!, updateAmmeter!: magnitude, variance;\n@ammeter: varianceFrom, varianceTo;\naddPmu!, updatePmu!: if from or to: magnitude, varianceMagnitude;\n@pmu: varianceMagnitudeFrom, varianceMagnitudeTo.\n\nChanging the unit of current angle is reflected in the following quantities:\n\naddPmu!, updatePmu!: if from or to: angle, varianceAngle;\n@pmu: varianceAngleFrom, varianceAngleTo.\n\nExample\n\n@current(pu, deg)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/#JuliaGrid.@parameter","page":"Setup and Print","title":"JuliaGrid.@parameter","text":"@parameter(impedance, admittance)\n\nJuliaGrid stores all data related with impedances and admittancies in per-units, and these cannot be altered. However, units of impedance and admittance of the built-in functions used to add or modified power system elements can be modified using the macro.\n\nPrefixes must be specified according to the SI prefixes and should be included with the unit of impedance (Ω) or unit of admittance (S). The second option is to define the units in per-unit (pu).\n\nIn the case where impedance and admittance are being used in SI units (Ω and S) and these units are related to the transformer, the assignment must be based on the primary side of the transformer.\n\nChanging the units of impedance is reflected in the following quantities in specific functions:\n\naddBranch!, updateBranch!, @branch: resistance, reactance.\n\nChanging the units of admittance is reflected in the following quantities:\n\naddBranch!, updateBranch!, @branch: conductance, susceptance.\n\nExample\n\n@parameter(Ω, pu)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Label-Types-2","page":"Setup and Print","title":"Label Types","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@labels","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@labels","page":"Setup and Print","title":"JuliaGrid.@labels","text":"@labels(type)\n\nJuliaGrid keeps all labels in ordered dictionaries as Strings. Users have the option to use Integers instead, which can be a more efficient way to store labels, particularly for large-scale systems.\n\nExample\n\n@labels(Integer)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Default-Settings-2","page":"Setup and Print","title":"Default Settings","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"@default","category":"page"},{"location":"api/setupPrint/#JuliaGrid.@default","page":"Setup and Print","title":"JuliaGrid.@default","text":"@default(mode)\n\nThe macro is designed to reset various settings to their default values.\n\nThe mode argument can take on the following values:\n\nunit: Resets all units to their default settings.\npower: Sets active, reactive, and apparent power to per-units.\nvoltage: Sets voltage magnitude to per-unit and voltage angle to radian.\nparameter: Sets impedance and admittance to per-units.\ntemplate: Resets bus, branch, generator, voltmeter, ammeter, wattmeter, varmeter, and pmu templates to their default settings.\nbus: Resets the bus template to its default settings.\nbranch: Resets the branch template to its default settings.\ngenerator: Resets the generator template to its default settings.\nvoltmeter: Resets the voltmeter template to its default settings.\nammeter: Resets the ammeter template to its default settings.\nwattmeter: Resets the wattmeter template to its default settings.\nvarmeter: Resets the varmeter template to its default settings.\npmu: Resets the pmu template to its default settings.\n\nExample\n\n@default(unit)\n\n\n\n\n\n","category":"macro"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintPowerSystemDataAPI","page":"Setup and Print","title":"Print Power System Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusData\nprintBranchData\nprintGeneratorData","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusData","page":"Setup and Print","title":"JuliaGrid.printBusData","text":"printBusData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints voltages, powers, and currents related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding bus.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all buses\nfmt = Dict(\"Power Demand\" => \"%.2f\", \"Voltage Magnitude\" => \"%.2f\", \"Label\" => \"%s\")\nshow = Dict(\"Power Injection\" => false, \"Power Generation Reactive\" => false)\nprintBusData(system, analysis; fmt, show, repeat = 10)\n\n# Print data for specific buses\ndelimiter = \" \"\nwidth = Dict(\"Voltage\" => 9, \"Power Injection Active\" => 9)\nprintBusData(system, analysis; label = 2, delimiter, width, title = true, header = true)\nprintBusData(system, analysis; label = 10, delimiter, width)\nprintBusData(system, analysis; label = 12, delimiter, width)\nprintBusData(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchData","page":"Setup and Print","title":"JuliaGrid.printBranchData","text":"printBranchData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints powers and currents related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding branch.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all branches\nfmt = Dict(\"Shunt Power\" => \"%.2f\", \"Series Power Reactive\" => \"%.2f\")\nshow = Dict(\"From-Bus Power\" => false, \"To-Bus Power Reactive\" => false)\nprintBranchData(system, analysis; fmt, show, repeat = 11, title = false)\n\n# Print data for specific branches\ndelimiter = \" \"\nwidth = Dict(\"From-Bus Power\" => 9, \"To-Bus Power Active\" => 9)\nprintBranchData(system, analysis; label = 2, delimiter, width, header = true)\nprintBranchData(system, analysis; label = 10, delimiter, width)\nprintBranchData(system, analysis; label = 12, delimiter, width)\nprintBranchData(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorData","page":"Setup and Print","title":"JuliaGrid.printGeneratorData","text":"printGeneratorData(system::PowerSystem, analysis::Analysis, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints powers related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding generator.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\n# Print data for all generators\nfmt = Dict(\"Power Output Active\" => \"%.2f\")\nshow = Dict(\"Power Output Reactive\" => false)\nprintGeneratorData(system, analysis; fmt, show, title = false)\n\n# Print data for specific generators\ndelimiter = \" \"\nwidth = Dict(\"Power Output Active\" => 7)\nprintGeneratorData(system, analysis; label = 1, delimiter, width, header = true)\nprintGeneratorData(system, analysis; label = 4, delimiter, width)\nprintGeneratorData(system, analysis; label = 5, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintPowerSystemSummaryAPI","page":"Setup and Print","title":"Print Power System Summary","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusSummary\nprintBranchSummary\nprintGeneratorSummary","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusSummary","page":"Setup and Print","title":"JuliaGrid.printBusSummary","text":"printBusSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style)\n\nThe function prints a summary of the electrical quantities related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"In-Use\" => false)\nprintBusSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchSummary","page":"Setup and Print","title":"JuliaGrid.printBranchSummary","text":"printBranchSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style))\n\nThe function prints a summary of the electrical quantities related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"Total\" => false)\nprintBranchSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorSummary","page":"Setup and Print","title":"JuliaGrid.printGeneratorSummary","text":"printGeneratorSummary(system::PowerSystem, analysis::Analysis, [io::IO];\n fmt, width, show, delimiter, title, header, footer, style)\n\nThe function prints a summary of the electrical quantities related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorSummary requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = newtonRaphson(system)\nfor i = 1:10\n stopping = mismatch!(system, analysis)\n if all(stopping .< 1e-8)\n break\n end\n solve!(system, analysis)\nend\npower!(system, analysis)\n\nshow = Dict(\"Minimum\" => false)\nprintGeneratorSummary(system, analysis; show, delimiter = \" \", title = false)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#Print-Measurement-Data-2","page":"Setup and Print","title":"Print Measurement Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printVoltmeterData\nprintAmmeterData\nprintWattmeterData\nprintVarmeterData\nprintPmuData","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printVoltmeterData","page":"Setup and Print","title":"JuliaGrid.printVoltmeterData","text":"printVoltmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to voltmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding voltmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all voltmeters\nfmt = Dict(\"Voltage Magnitude\" => \"%.2f\", \"Voltage Magnitude Estimate\" => \"%.6f\")\nshow = Dict(\"Voltage Magnitude Residual\" => false)\nprintVoltmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific voltmeters\nwidth = Dict(\"Voltage Magnitude Estimate\" => 11)\nprintVoltmeterData(system, device, analysis; label = 1, width, header = true)\nprintVoltmeterData(system, device, analysis; label = 6, width)\nprintVoltmeterData(system, device, analysis; label = 8, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printAmmeterData","page":"Setup and Print","title":"JuliaGrid.printAmmeterData","text":"printAmmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to ammeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding ammeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\ncurrent!(system, analysis)\n\n# Print data for all ammeters\nfmt = Dict(\"Current Magnitude\" => \"%.2f\", \"Current Magnitude Estimate\" => \"%.6f\")\nshow = Dict(\"Current Magnitude Residual\" => false)\nprintAmmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific ammeters\nwidth = Dict(\"Current Magnitude\" => 10)\nprintAmmeterData(system, device, analysis; label = \"From 1\", width, header = true)\nprintAmmeterData(system, device, analysis; label = \"From 4\", width)\nprintAmmeterData(system, device, analysis; label = \"From 6\", width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printWattmeterData","page":"Setup and Print","title":"JuliaGrid.printWattmeterData","text":"printWattmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to wattmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding wattmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all wattmeters\nfmt = Dict(\"Active Power\" => \"%.2f\", \"Active Power Estimate\" => \"%.6f\")\nshow = Dict(\"Active Power Status\" => false)\nprintWattmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 14)\n\n# Print data for specific wattmeters\nwidth = Dict(\"Active Power Residual\" => 11)\nprintWattmeterData(system, device, analysis; label = 2, width, header = true)\nprintWattmeterData(system, device, analysis; label = 5, width)\nprintWattmeterData(system, device, analysis; label = 9, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printVarmeterData","page":"Setup and Print","title":"JuliaGrid.printVarmeterData","text":"printVarmeterData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to varmeters. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding varmeter.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\npower!(system, analysis)\n\n# Print data for all wattmeters\nfmt = Dict(\"Reactive Power\" => \"%.2f\", \"Reactive Power Estimate\" => \"%.6f\")\nshow = Dict(\"Reactive Power Status\" => false)\nprintVarmeterData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 14)\n\n# Print data for specific wattmeters\nwidth = Dict(\"Reactive Power Residual\" => 11)\nprintVarmeterData(system, device, analysis; label = 2, width, header = true)\nprintVarmeterData(system, device, analysis; label = 5, width)\nprintVarmeterData(system, device, analysis; label = 9, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printPmuData","page":"Setup and Print","title":"JuliaGrid.printPmuData","text":"printPmuData(system::PowerSystem, device::Measurement, [analysis::Analysis],\n [io::IO]; label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints data related to PMUs. Optionally, an IO may be passed as the last argument to redirect the output. Users can also omit the Analysis type to print only data related to the Measurement type.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding PMU.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printPmuData requires Julia 1.10 or later.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\ncurrent!(system, analysis)\n\n# Print data for all PMUs\nfmt = Dict(\"Current Magnitude\" => \"%.2f\", \"Current Magnitude Variance\" => \"%.5f\")\nshow = Dict(\"Current Angle\" => false, \"Current Magnitude Status\" => false)\nprintPmuData(system, device, analysis; fmt, show, delimiter = \" \", repeat = 10)\n\n# Print data for specific PMUs\nwidth = Dict(\"Current Magnitude\" => 10, \"Current Angle Status\" => 8)\nprintPmuData(system, device, analysis; label = \"From 1\", width, header = true)\nprintPmuData(system, device, analysis; label = \"From 4\", width)\nprintPmuData(system, device, analysis; label = \"From 6\", width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"","category":"page"},{"location":"api/setupPrint/#PrintConstraintDataAPI","page":"Setup and Print","title":"Print Constraint Data","text":"","category":"section"},{"location":"api/setupPrint/","page":"Setup and Print","title":"Setup and Print","text":"printBusConstraint\nprintBranchConstraint\nprintGeneratorConstraint","category":"page"},{"location":"api/setupPrint/#JuliaGrid.printBusConstraint","page":"Setup and Print","title":"JuliaGrid.printBusConstraint","text":"printBusConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to buses. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding bus.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBusConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all buses\nfmt = Dict(\"Active Power Balance\" => \"%.2e\", \"Reactive Power Balance Dual\" => \"%.4e\")\nshow = Dict(\"Voltage Magnitude\" => false, \"Reactive Power Balance Solution\" => false)\nprintBusConstraint(system, analysis; fmt, show, repeat = 10)\n\n# Print data for specific buses\ndelimiter = \" \"\nwidth = Dict(\"Voltage Magnitude\" => 8, \"Active Power Balance Solution\" => 12)\nprintBusConstraint(system, analysis; label = 2, delimiter, width, header = true)\nprintBusConstraint(system, analysis; label = 10, delimiter, width)\nprintBusConstraint(system, analysis; label = 14, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printBranchConstraint","page":"Setup and Print","title":"JuliaGrid.printBranchConstraint","text":"printBranchConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to branches. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding branch.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printBranchConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\nupdateBranch!(system; label = 3, minDiffAngle = 0.05, maxDiffAngle = 1.5)\nupdateBranch!(system; label = 4, minDiffAngle = 0.05, maxDiffAngle = 1.1)\nupdateBranch!(system; label = 4, maxFromBus = 0.4, maxToBus = 0.5)\nupdateBranch!(system; label = 9, minFromBus = 0.1, maxFromBus = 0.3)\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all branches\nfmt = Dict(\"Voltage Angle Difference\" => \"%.2f\")\nshow = Dict(\"To-Bus Apparent Power Flow Dual\" => false)\nprintBranchConstraint(system, analysis; fmt, show, repeat = 2)\n\n# Print data for specific branches\ndelimiter = \" \"\nwidth = Dict(\"From-Bus Apparent Power Flow\" => 13, \"Voltage Angle Difference Dual\" => 12)\nprintBranchConstraint(system, analysis; label = 3, delimiter, width, header = true)\nprintBranchConstraint(system, analysis; label = 4, delimiter, width)\nprintBranchConstraint(system, analysis; label = 9, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/setupPrint/#JuliaGrid.printGeneratorConstraint","page":"Setup and Print","title":"JuliaGrid.printGeneratorConstraint","text":"printGeneratorConstraint(system::PowerSystem, analysis::OptimalPowerFlow, [io::IO];\n label, fmt, width, show, delimiter, title, header, footer, repeat, style)\n\nThe function prints constraint data related to generators. Optionally, an IO may be passed as the last argument to redirect the output.\n\nKeywords\n\nThe following keywords control the printed data:\n\nlabel: Prints only the data for the corresponding generator.\nfmt: Specifies the preferred numeric formats or alignments for the columns.\nwidth: Specifies the preferred widths for the columns.\nshow: Toggles the printing of the columns.\ndelimiter: Sets the column delimiter.\ntitle: Toggles the printing of the table title.\nheader: Toggles the printing of the header.\nfooter: Toggles the printing of the footer.\nrepeat: Prints the header again after a specified number of lines have been printed.\nstyle: Prints either a stylish table or a simple table suitable for easy export.\n\ncompat: Julia 1.10\nThe function printGeneratorConstraint requires Julia 1.10 or later.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n# Print data for all generators\nfmt = Dict(\"Active Power Capability\" => \"%.2f\")\nshow = Dict(\"Reactive Power Capability\" => false, \"Active Power Capability Dual\" => false)\nprintGeneratorConstraint(system, analysis; fmt, show, repeat = 3)\n\n# Print data for specific generators\ndelimiter = \" \"\nwidth = Dict(\"Active Power Capability\" => 11, \"Reactive Power Capability Dual\" => 10)\nprintGeneratorConstraint(system, analysis; label = 2, delimiter, width, header = true)\nprintGeneratorConstraint(system, analysis; label = 3, delimiter, width)\nprintGeneratorConstraint(system, analysis; label = 5, delimiter, width, footer = true)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#StateEstimationAPI","page":"State Estimation","title":"State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"For further information on this topic, please see the AC State Estimation, PMU State Estimation or DC State Estimation sections of the Manual. Below, we have provided a list of functions that can be utilized for state estimation, observability analysis, or bad data processing.","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"To load state estimation API functionalities into the current scope, utilize the following command:","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"using JuliaGrid","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Observability-Analysis","page":"State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"islandTopologicalFlow\nislandTopological\nrestorationGram!","category":"page"},{"location":"api/stateEstimation/#AC-State-Estimation","page":"State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"gaussNewton\nacLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#PMU-State-Estimation","page":"State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"pmuPlacement\npmuStateEstimation\npmuLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#DC-State-Estimation","page":"State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"dcStateEstimation\ndcLavStateEstimation\nsolve!","category":"page"},{"location":"api/stateEstimation/#Bad-Data-Analysis","page":"State Estimation","title":"Bad Data Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"residualTest!","category":"page"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Observability-Analysis-2","page":"State Estimation","title":"Observability Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"islandTopologicalFlow(::PowerSystem, ::Measurement)\nislandTopological(::PowerSystem, ::Measurement)\nrestorationGram!(::PowerSystem, ::Measurement, ::Measurement, ::Island)","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.islandTopologicalFlow-Tuple{PowerSystem, Measurement}","page":"State Estimation","title":"JuliaGrid.islandTopologicalFlow","text":"islandTopologicalFlow(system::PowerSystem, device::Measurement)\n\nThe function utilizes a topological approach to detect flow observable islands, resulting in the formation of disconnected and loop-free subgraphs. It is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.\n\nArguments\n\nTo define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.\n\nReturns\n\nThe function returns an Island type, containing information about the islands:\n\nisland: List enumerating observable islands with indices of buses.\nbus: Positions of buses in relation to each island.\ntie: Tie data associated with buses and branches.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 15)\ndevice.varmeter.reactive.status = copy(device.wattmeter.active.status)\n\nislands = islandTopologicalFlow(system, device)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/#JuliaGrid.islandTopological-Tuple{PowerSystem, Measurement}","page":"State Estimation","title":"JuliaGrid.islandTopological","text":"islandTopological(system::PowerSystem, meter::Measurement)\n\nThe function employs a topological method to identify maximal observable islands. Specifically, it employs active power measurements to pinpoint flow observable islands. Subsequently, these islands are merged based on the available injection measurements.\n\nIt is assumed that active and reactive power measurements are paired, indicating a standard observability analysis. In this analysis, islands formed by active power measurements correspond to those formed by reactive power measurements.\n\nArguments\n\nTo define flow observable islands, this function necessitates the composite types PowerSystem and Measurement.\n\nReturns\n\nThe function returns an Island type, containing information about the islands:\n\nisland: List enumerating observable islands with indices of buses.\nbus: Positions of buses in relation to each island.\ntie: Tie data associated with buses and branches.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 15)\ndevice.varmeter.reactive.status = copy(device.wattmeter.active.status)\n\nislands = islandTopological(system, device)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/#JuliaGrid.restorationGram!-Tuple{PowerSystem, Measurement, Measurement, Island}","page":"State Estimation","title":"JuliaGrid.restorationGram!","text":"restorationGram!(system::PowerSystem, device::Measurement, pseudo::Measurement,\n islands::Island; threshold)\n\nUpon identifying the islands, the function incorporates measurements from the available pseudo-measurements in the pseudo variable into the device variable to reinstate observability. This method relies on reduced coefficient matrices and the Gram matrix.\n\nIt is important to note that the device labels in the device and pseudo variables must be different to enable the function to successfully incorporate measurements from pseudo into the device set of measurements.\n\nKeyword\n\nThe keyword threshold defines the zero pivot threshold value, with a default value of 1e-5. More precisely, all computed pivots less than this value will be treated as zero pivots.\n\nUpdates\n\nThe function updates the device variable of the Measurement composite type.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\npseudo = measurement(\"pseudomeasurement14.h5\")\n\nstatusWattmeter!(system, device; inservice = 10)\nislands = islandTopological(system, device)\n\nrestorationGram!(system, device, pseudo, islands)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#AC-State-Estimation-2","page":"State Estimation","title":"AC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"gaussNewton\nacLavStateEstimation\nsolve!(::PowerSystem, ::ACStateEstimation{NonlinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.gaussNewton","page":"State Estimation","title":"JuliaGrid.gaussNewton","text":"gaussNewton(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function sets up the Gauss-Newton method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates. The Gauss-Newton method throughout iterations provided WLS estimator.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the nonlinear WLS state estimation framework.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the ACStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the AC state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\n\nSet up the AC state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.acLavStateEstimation","page":"State Estimation","title":"JuliaGrid.acLavStateEstimation","text":"acLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function sets up the LAV method to solve the nonlinear or AC state estimation model, where the vector of state variables is given in polar coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the ACStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, ACStateEstimation{NonlinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::ACStateEstimation)\n\nBy computing the bus voltage magnitudes and angles, the function solves the AC state estimation model.\n\nUpdates\n\nThe resulting bus voltage magnitudes and angles are stored in the voltage field of the ACStateEstimation type.\n\nExamples\n\nSolving the AC state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = gaussNewton(system, device)\nfor iteration = 1:20\n stopping = solve!(system, analysis)\n if stopping < 1e-8\n break\n end\nend\n\nSolving the AC state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = acLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#PMU-State-Estimation-2","page":"State Estimation","title":"PMU State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"pmuPlacement\npmuStateEstimation\npmuLavStateEstimation\nsolve!(::PowerSystem, ::PMUStateEstimation{LinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.pmuPlacement","page":"State Estimation","title":"JuliaGrid.pmuPlacement","text":"pmuPlacement(system::PowerSystem, optimizer; bridge)\n\nThe function determines the optimal placement of PMUs through integer linear programming. Specifically, it identifies the minimum set of PMU locations required for effective power system state estimation, ensuring observability with the least number of PMUs.\n\nThe function accepts a PowerSystem composite type as input to establish the framework for finding the optimal PMU placement. If the ac field within the PowerSystem composite type is not yet created, the function automatically initiates an update process.\n\nAdditionally, the optimizer argument is a crucial component for formulating and solving the optimization problem. Typically, using the GLPK or HiGHS solver is sufficient. For more detailed information, please refer to the JuMP documenatation.\n\nKeyword\n\nThe bridge keyword enables users to manage the bridging mechanism within the JuMP package.\n\nReturns\n\nThe function returns an instance of the PlacementPMU type, containing variables such as:\n\nbus: Bus labels with indices marking the positions of PMUs at buses.\nfrom: Branch labels with indices marking the positions of PMUs at from-bus ends.\nto: Branch labels with indices marking the positions of PMUs at to-bus ends.\n\nNote that if the conventional understanding of a PMU involves a device measuring the bus voltage phasor and all branch current phasors incident to the bus, the result is saved only in the bus variable. However, if we consider that a PMU measures individual phasors, each described with magnitude and angle, then measurements are needed at each bus in the bus variable, and each branch with positions given according to from and to variables.\n\nExample\n\nusing GLPK, Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement()\n\nanalysis = acOptimalPowerFlow(system, Ipopt.Optimizer)\nsolve!(system, analysis)\ncurrent!(system, analysis)\n\nplacement = pmuPlacement(system, GLPK.Optimizer)\n\n@pmu(label = \"PMU ?: !\")\nfor (bus, i) in placement.bus\n Vi, θi = analysis.voltage.magnitude[i], analysis.voltage.angle[i]\n addPmu!(system, device; bus = bus, magnitude = Vi, angle = θi)\nend\nfor branch in keys(placement.from)\n Iij, ψij = fromCurrent(system, analysis; label = branch)\n addPmu!(system, device; from = branch, magnitude = Iij, angle = ψij)\nend\nfor branch in keys(placement.to)\n Iji, ψji = toCurrent(system, analysis; label = branch)\n addPmu!(system, device; to = branch, magnitude = Iji, angle = ψji)\nend\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.pmuStateEstimation","page":"State Estimation","title":"JuliaGrid.pmuStateEstimation","text":"pmuStateEstimation(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function establishes the linear WLS model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the PMU state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device)\n\nSet up the PMU state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.pmuLavStateEstimation","page":"State Estimation","title":"JuliaGrid.pmuLavStateEstimation","text":"pmuLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function establishes the LAV model for state estimation with PMUs only. In this model, the vector of state variables contains bus voltages, given in rectangular coordinates.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the AC model has not been created, the function will automatically trigger an update of the ac field within the PowerSystem composite type.\n\nReturns\n\nThe function returns an instance of the PMUStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage magnitudes and angles.\npower: The variable allocated to store the active and reactive powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, PMUStateEstimation{LinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::PMUStateEstimation)\n\nBy computing the bus voltage magnitudes and angles, the function solves the PMU state estimation model.\n\nUpdates\n\nThe resulting bus voltage magnitudes and angles are stored in the voltage field of the PMUStateEstimation type.\n\nExamples\n\nSolving the PMU state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuStateEstimation(system, device)\nsolve!(system, analysis)\n\nSolving the PMU state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = pmuLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#DC-State-Estimation-2","page":"State Estimation","title":"DC State Estimation","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"dcStateEstimation\ndcLavStateEstimation\nsolve!(::PowerSystem, ::DCStateEstimation{LinearWLS{Normal}})","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.dcStateEstimation","page":"State Estimation","title":"JuliaGrid.dcStateEstimation","text":"dcStateEstimation(system::PowerSystem, device::Measurement, [method = LU])\n\nThe function establishes the WLS model for DC state estimation, where the vector of state variables contains only bus voltage angles.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the WLS state estimation model.\n\nMoreover, the presence of the method parameter is not mandatory. To address the WLS state estimation method, users can opt to utilize factorization techniques to decompose the gain matrix, such as LU, QR, or LDLt especially when the gain matrix is symmetric. Opting for the Orthogonal method is advisable for a more robust solution in scenarios involving ill-conditioned data, particularly when substantial variations in variances are present.\n\nIf the user does not provide the method, the default method for solving the estimation model will be LU factorization.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCStateEstimation type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The system model vectors and matrices.\n\nExamples\n\nSet up the DC state estimation model to be solved using the default LU factorization:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\n\nSet up the DC state estimation model to be solved using the orthogonal method:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device, Orthogonal)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.dcLavStateEstimation","page":"State Estimation","title":"JuliaGrid.dcLavStateEstimation","text":"dcLavStateEstimation(system::PowerSystem, device::Measurement, optimizer)\n\nThe function establishes the LAV model for DC state estimation, where the vector of state variables contains only bus voltage angles.\n\nArguments\n\nThis function requires the PowerSystem and Measurement composite types to establish the LAV state estimation model. The LAV method offers increased robustness compared to WLS, ensuring unbiasedness even in the presence of various measurement errors and outliers.\n\nUsers can employ the LAV method to find an estimator by choosing one of the available optimization solvers. Typically, Ipopt.Optimizer suffices for most scenarios.\n\nUpdates\n\nIf the DC model was not created, the function will automatically initiate an update of the dc field within the PowerSystem composite type. Additionally, if the slack bus lacks an in-service generator, JuliaGrid considers it a mistake and defines a new slack bus as the first generator bus with an in-service generator in the bus type list.\n\nReturns\n\nThe function returns an instance of the DCStateEstimation abstract type, which includes the following fields:\n\nvoltage: The variable allocated to store the bus voltage angles.\npower: The variable allocated to store the active powers.\nmethod: The optimization model.\n\nExample\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\n\n\n\n\n\n","category":"function"},{"location":"api/stateEstimation/#JuliaGrid.solve!-Tuple{PowerSystem, DCStateEstimation{LinearWLS{Normal}}}","page":"State Estimation","title":"JuliaGrid.solve!","text":"solve!(system::PowerSystem, analysis::DCStateEstimation)\n\nBy computing the bus voltage angles, the function solves the DC state estimation model.\n\nUpdates\n\nThe resulting bus voltage angles are stored in the voltage field of the DCStateEstimation type.\n\nExamples\n\nSolving the DC state estimation model and obtaining the WLS estimator:\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\n\nSolving the DC state estimation model and obtaining the LAV estimator:\n\nusing Ipopt\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcLavStateEstimation(system, device, Ipopt.Optimizer)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"method"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"","category":"page"},{"location":"api/stateEstimation/#Bad-Data-Analysis-2","page":"State Estimation","title":"Bad Data Analysis","text":"","category":"section"},{"location":"api/stateEstimation/","page":"State Estimation","title":"State Estimation","text":"residualTest!","category":"page"},{"location":"api/stateEstimation/#JuliaGrid.residualTest!","page":"State Estimation","title":"JuliaGrid.residualTest!","text":"residualTest!(system::PowerSystem, device::Measurement, analysis::StateEstimation;\n threshold)\n\nThe function conducts bad data detection and identification using the largest normalized residual test, subsequently removing measurement outliers from the measurement set. It can be executed after obtaining WLS estimator.\n\nArguments\n\nThis function requires the types PowerSystem, Measurement, and StateEstimation. The abstract type StateEstimation can have the following subtypes:\n\nACStateEstimation: Conducts bad data analysis within AC state estimation.\nPMUStateEstimation: Conducts bad data analysis within PMU state estimation.\nDCStateEstimation: Conducts bad data analysis within DC state estimation.\n\nKeyword\n\nThe keyword threshold establishes the identification threshold. If the largest normalized residual surpasses this threshold, the measurement is flagged as bad data. The default threshold value is set to threshold = 3.0.\n\nUpdates\n\nIf bad data is detected, the function flags the corresponding measurement within the Measurement type as out-of-service.\n\nMoreover, for DCStateEstimation and PMUStateEstimation types, the function removes the corresponding measurement from the coefficient matrix and mean vector. This facilitates direct progress to the function that solves the state estimation problem.\n\nReturns\n\nThe function returns an instance of the BadData type, which includes:\n\ndetect: Returns true after the function's execution if bad data is detected.\nmaxNormalizedResidual: Denotes the value of the largest normalized residual.\nlabel: Signifies the label of the bad data.\nindex: Represents the index of the bad data.\n\nExample\n\nsystem = powerSystem(\"case14.h5\")\ndevice = measurement(\"measurement14.h5\")\n\nanalysis = dcStateEstimation(system, device)\nsolve!(system, analysis)\n\noutlier = residualTest!(system, device, analysis; threshold = 4.0)\nsolve!(system, analysis)\n\n\n\n\n\n","category":"function"}] } diff --git a/dev/tutorials/acOptimalPowerFlow/index.html b/dev/tutorials/acOptimalPowerFlow/index.html index 4fe8cd2f..603cf6d0 100644 --- a/dev/tutorials/acOptimalPowerFlow/index.html +++ b/dev/tutorials/acOptimalPowerFlow/index.html @@ -155,4 +155,4 @@ 0.08571441475064301
julia> 𝛙ⱼ = analysis.current.to.angle1-element Vector{Float64}: -1.6707962111927632
Current at Branch Series Elements

To obtain the vectors of magnitudes $\mathbf{I}_{\text{l}} = [I_{\text{l}ij}]$ and angles $\bm{\psi}_{\text{l}} = [\psi_{\text{l}ij}]$ of the resulting complex current flows, one can use the following code:

julia> 𝐈ₗ = analysis.current.series.magnitude1-element Vector{Float64}:
  0.08571441475064301
julia> 𝛙ₗ = analysis.current.series.angle1-element Vector{Float64}: - 1.4707964423970301
+ 1.4707964423970301 diff --git a/dev/tutorials/acPowerFlow/index.html b/dev/tutorials/acPowerFlow/index.html index aa1c2763..358b23ae 100644 --- a/dev/tutorials/acPowerFlow/index.html +++ b/dev/tutorials/acPowerFlow/index.html @@ -454,4 +454,4 @@ 1.0533688181418344 1.798915816381931 2.1060717428167246 - 1.3809084790963575 + 1.3809084790963575 diff --git a/dev/tutorials/acStateEstimation/index.html b/dev/tutorials/acStateEstimation/index.html index 5b5e26e5..562dd923 100644 --- a/dev/tutorials/acStateEstimation/index.html +++ b/dev/tutorials/acStateEstimation/index.html @@ -558,4 +558,4 @@ 0.7891003404573693 0.0969541517042328 -1.2553086990431555 - -0.16797520542382388 + -0.16797520542382388 diff --git a/dev/tutorials/dcOptimalPowerFlow/index.html b/dev/tutorials/dcOptimalPowerFlow/index.html index 5adb36a8..0e14bae0 100644 --- a/dev/tutorials/dcOptimalPowerFlow/index.html +++ b/dev/tutorials/dcOptimalPowerFlow/index.html @@ -96,4 +96,4 @@ 0.025000000000002798

Similarly, the resulting to-bus active power flows are stored as the vector $\mathbf{P}_{\text{j}} = [P_{ji}]$, which can be retrieved using:

julia> 𝐏ⱼ = analysis.power.to.active3-element Vector{Float64}:
   5.551115123125783e-16
  -0.025000000000000022
- -0.025000000000002798
+ -0.025000000000002798 diff --git a/dev/tutorials/dcPowerFlow/index.html b/dev/tutorials/dcPowerFlow/index.html index 36791421..cb617626 100644 --- a/dev/tutorials/dcPowerFlow/index.html +++ b/dev/tutorials/dcPowerFlow/index.html @@ -46,4 +46,4 @@ 0.09337060504410487
Generators Power Outputs

The output active power of each generator located at bus $i \in \mathcal{N}_{\text{pv}} \cup \mathcal{N}_{\text{pq}}$ is equal to the active power specified in the input data. If there are multiple generators, their output active powers are also equal to the active powers specified in the input data. However, the output active power of a generator located at the slack bus will be:

\[ P_{\text{g}i} = P_i + P_{\text{d}i},\;\;\; i \in \mathcal{N}_{\text{sb}}.\]

In the case of multiple generators connected to the slack bus, the first generator in the input data is assigned the obtained value of $P_{\text{g}i}$. Then, this amount of power is reduced by the output active power of the other generators.

To retrieve the vector of active power outputs of generators, denoted as $\mathbf{P}_{\text{g}} = [P_{\text{g}i}]$, $i \in \mathcal{S}$, where the set $\mathcal{S}$ represents the set of generators, users can utilize the following command:

julia> 𝐏ₒ = analysis.power.generator.active3-element Vector{Float64}:
  0.12769999999999998
  0.04
- 0.05
+ 0.05 diff --git a/dev/tutorials/dcStateEstimation/index.html b/dev/tutorials/dcStateEstimation/index.html index d41ffbd7..3041ae26 100644 --- a/dev/tutorials/dcStateEstimation/index.html +++ b/dev/tutorials/dcStateEstimation/index.html @@ -97,4 +97,4 @@ 0.18500000000007344

Similarly, the resulting active power flows are stored as the vector $\mathbf{P}_{\text{j}} = [P_{ji}]$, which can be retrieved using:

julia> 𝐏ⱼ = analysis.power.to.active3-element Vector{Float64}:
  -0.2799999999995778
  -1.1149999999993758
- -0.18500000000007344
+ -0.18500000000007344 diff --git a/dev/tutorials/measurementModel/index.html b/dev/tutorials/measurementModel/index.html index 82cea805..aa508c4a 100644 --- a/dev/tutorials/measurementModel/index.html +++ b/dev/tutorials/measurementModel/index.html @@ -21,7 +21,7 @@ "V₁" "V₃"

This set of voltmeters defines vectors of measurement values denoted as $\mathbf{z}_\mathcal{V} = [z_i]$ and variances denoted as $\mathbf{v}_\mathcal{V} = [v_i]$, where $i \in \mathcal{V}$, and can be accessed through the following variables:

julia> 𝐳ᵥ = device.voltmeter.magnitude.mean2-element Vector{Float64}:
  1.1
- 0.922685495444675
julia> 𝐯ᵥ = device.voltmeter.magnitude.variance2-element Vector{Float64}: + 0.9799790983199244
julia> 𝐯ᵥ = device.voltmeter.magnitude.variance2-element Vector{Float64}: 0.001 0.01

Ammeters

An ammeter $I_{ij} \in \mathcal{I}$ measures the magnitude of branch current at the from-bus end of the branch $(i,j) \in \mathcal{E}$. Let us add this type of ammeter at the first branch between buses 1 and 2:

addAmmeter!(system, device; label = "I₁₂", from = 1, magnitude = 0.3, variance = 1e-3)

Additionally, an ammeter can measure the branch current magnitude at the to-bus end of the branch $(i,j) \in \mathcal{E}$, denoted as $I_{ji} \in \mathcal{I}$. For example, we can include this type of ammeter at the same branch:

addAmmeter!(system, device; label = "I₂₁", to = 1, magnitude = 0.2, variance = 1e-3)

Consequently, we establish the set of ammeters $\mathcal{I} \subset \mathcal{M}$:

julia> ℐ = collect(keys(device.ammeter.label))2-element Vector{String}:
  "I₁₂"
@@ -44,15 +44,15 @@
  "Q₂₁"

This set of varmeters defines vectors of measurement values denoted as $\mathbf{z}_\mathcal{Q} = [z_i]$ and variances denoted as $\mathbf{v}_\mathcal{Q} = [v_i]$, where $i \in \mathcal{Q}$, and can be accessed through the following variables:

julia> 𝐳ₒ = device.varmeter.reactive.mean3-element Vector{Float64}:
   0.01
   0.02
- -0.0052552692710675294
julia> 𝐯ₒ = device.varmeter.reactive.variance3-element Vector{Float64}: + -0.01806020414915807
julia> 𝐯ₒ = device.varmeter.reactive.variance3-element Vector{Float64}: 0.01 0.001 0.01

PMUs

PMUs measure voltage and current phasors in the polar coordinate system, thus each PMU output is represented by magnitude and angle along with corresponding variances [14, Sec. 5.6]. When installed on buses, they measure bus voltage phasors, while on branches, they measure current phasors.

A PMU $(V_i, \theta_i) \in \bar{\mathcal{P}}$ measures the voltage phasor at bus $i \in \mathcal{N}$. Let us integrate this type of PMU at the first bus:

addPmu!(system, device; label = "V₁, θ₁", bus = 1, magnitude = 1, angle = 0, noise = true)

Next, a PMU $(I_{ij}, \psi_{ij}) \in \bar{\mathcal{P}}$ measures the branch current magnitude at the from-bus end of the branch $(i,j) \in \mathcal{E}$. Let us add this type of PMU at the first branch:

addPmu!(system, device; label = "I₁₂, ψ₁₂", from = 1, magnitude = 0.2, angle = -0.1)

Moreover, a PMU can measure the branch current magnitude at the to-bus end of the branch $(i,j) \in \mathcal{E}$, denoted as $(I_{ji}, \psi_{ji}) \in \bar{\mathcal{P}}$. For example, let us include this type of PMU at the same branch:

addPmu!(system, device; label = "I₂₁, ψ₂₁", to = 1, magnitude = 0.3, angle = -0.2)

Consequently, we establish the set of PMUs $\bar{\mathcal{P}} \subset \mathcal{M}$:

julia> 𝒫̄ = collect(keys(device.pmu.label))3-element Vector{String}:
  "V₁, θ₁"
  "I₁₂, ψ₁₂"
  "I₂₁, ψ₂₁"

This set of PMUs establishes vectors representing measurement magnitudes and angles $\mathbf{z}_{\bar{\mathcal{P}}} = [z_i, z_j]$, along with their corresponding variances $\mathbf{v}_{\bar{\mathcal{P}}} = [v_i, v_j]$, where $(i, j) \in \bar{\mathcal{P}}$. These values can be accessed as:

julia> pmu = device.pmu;
julia> 𝐳ₚ = collect(Iterators.flatten(zip(pmu.magnitude.mean, pmu.angle.mean)))6-element Vector{Float64}: - 1.0009486282151179 - -0.0019202744782120095 + 1.0022737575583422 + -0.005616137790814315 0.2 -0.1 0.3 @@ -64,4 +64,4 @@ 1.0e-5 1.0e-5
Info

PMUs can be handled in state estimation algorithms according to our definition in polar coordinate systems. However, they can also be processed in rectangular coordinates, where we observe the real and imaginary parts of the phasor measurements rather than magnitude and angle. Further details can be found in tutorials that describe specific state estimation analyses.


State Estimation

After establishing the measurement model, which includes specifying measurement values, variances, the locations of measurement devices, and known power system network parameters, the subsequent step involves the process of state estimation. State estimation is a component of energy management systems and typically encompasses network topology processing, observability analysis, state estimation algorithms, and bad data analysis.

The primary goal of state estimation algorithms is to determine state variables, often associated with bus voltages. Therefore, by representing the vector of state variables as $\mathbf{x}$ and the vector of noisy measurement values as $\mathbf{z}$, we can effectively describe the state estimation problem using the following conditional probability equation:

\[ p(\mathbf{x}|\mathbf{z})= \cfrac{p(\mathbf{z}|\mathbf{x})p(\mathbf{x})}{p(\mathbf{z})}.\]

If we assume that the prior probability distribution $p(\mathbf{x})$ is uniform and that $p(\mathbf{z})$ does not depend on $\mathbf{x}$, the maximum a posteriori solution simplifies to the maximum likelihood solution, as shown below [15]:

\[ \hat{\mathbf{x}} = \mathrm{arg}\max_{\mathbf{x}}p(\mathbf{x}|\mathbf{z}) = \mathrm{arg}\max_{\mathbf{x}}p(\mathbf{z}|\mathbf{x}) = \mathrm{arg}\max_{\mathbf{x}}\mathcal{L}(\mathbf{z}|\mathbf{x}).\]

We can find this solution by maximizing the likelihood function $\mathcal{L}(\mathbf{z}|\mathbf{x})$, which is defined based on the likelihoods of $k$ independent measurements:

\[ \hat{\mathbf x} = \mathrm{arg} \max_{\mathbf{x}}\mathcal{L}(\mathbf{z}|\mathbf{x})= - \mathrm{arg} \max_{\mathbf{x}} \prod_{i=1}^k \mathcal{N}(z_i|\mathbf{x},v_i).\]

It can be demonstrated that the solution to the maximum a posteriori problem can be obtained by solving the following optimization problem, commonly referred to as the weighted least-squares problem [9, Sec. 9.3]:

\[ \hat{\mathbf x} = \mathrm{arg}\min_{\mathbf{x}} \sum_{i=1}^k\cfrac{[z_i-h_i(\mathbf x)]^2}{v_i}.\]

The state estimate, denoted as $\hat{\mathbf x}$, resulting from the solution to the above optimization problem, is known as the weighted least-squares estimator. Both the maximum likelihood and weighted least-squares estimators are equivalent to the maximum a posteriori solution [15, Sec. 8.6].

+ \mathrm{arg} \max_{\mathbf{x}} \prod_{i=1}^k \mathcal{N}(z_i|\mathbf{x},v_i).\]

It can be demonstrated that the solution to the maximum a posteriori problem can be obtained by solving the following optimization problem, commonly referred to as the weighted least-squares problem [9, Sec. 9.3]:

\[ \hat{\mathbf x} = \mathrm{arg}\min_{\mathbf{x}} \sum_{i=1}^k\cfrac{[z_i-h_i(\mathbf x)]^2}{v_i}.\]

The state estimate, denoted as $\hat{\mathbf x}$, resulting from the solution to the above optimization problem, is known as the weighted least-squares estimator. Both the maximum likelihood and weighted least-squares estimators are equivalent to the maximum a posteriori solution [15, Sec. 8.6].

diff --git a/dev/tutorials/perunit/index.html b/dev/tutorials/perunit/index.html index b682fe45..a8d66a11 100644 --- a/dev/tutorials/perunit/index.html +++ b/dev/tutorials/perunit/index.html @@ -1,2 +1,2 @@ -Per-Unit System · JuliaGrid

Per-Unit System

In power system modeling and analysis, variables and parameters are often normalized using the per-unit system. The per-unit system is particularly advantageous for analyzing networks with multiple voltage levels connected by transformers with different turns ratios.

In static scenarios, there are four key quantities of interest: voltage, current, power, and impedance or admittance. Defining a per-unit system requires selecting base values for each of these quantities. However, since these quantities are interconnected by various laws, the choice of base values cannot be arbitrary. Typically, the base quantities are chosen as voltage and power, with the base current and impedance (or admittance) then calculated accordingly. Usually, base quantities are selected as follows:

  • three-phase apparent power $S_{3\phi(\text{b})}$,
  • line-to-line voltage $V_{LL(\text{b})}$.

While the value of three-phase apparent power is unique across the entire system, multiple line-to-line base voltages are used to account for the different voltage zones created by transformers.

Info

Since balanced three-phase power systems are treated as a single line with a neutral return, confusion may arise regarding the relationship between the per-unit values of line voltages and phase voltages, as well as between the per-unit values of single-phase and three-phase powers [7]. To clarify these relationships, we will systematically explore the conversions between the per-unit and SI systems below.


Powers

Let us consider the three-phase apparent power expressed in SI units, denoted as $S_{3\phi(\text{si})}$. To convert this into the per-unit system, we divide it by the base power:

\[S_{3\phi(\text{pu})} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}}.\]

Now, let us examine the power of a single phase and convert it to the per-unit system:

\[S_{1\phi(\text{pu})} = \cfrac{S_{1\phi(\text{si})}}{S_{1\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{3} \cfrac{3}{S_{3\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}} = S_{3\phi(\text{pu})}.\]

This indicates that in the per-unit system, there is no distinction between three-phase and single-phase powers. The type of power only becomes relevant when converting back from per-unit to SI units, and vice versa.

Info

As is standard practice, even if all simulations utilize a single-phase equivalent, input powers provided in SI units are assumed to represent three-phase powers. Similarly, if simulation results are displayed in SI units, they are considered to be three-phase powers, as we have selected three-phase power as the base value.


Voltages

Format for input data that JuliaGrid uses required value for base voltage per each bus, and those values represent the line-to-line voltages. On the other hand, in all analyses we are working with line-to-neutral voltages. To convert a line-to-neutral voltage given in SI units $V_{LN(\text{si})}$ to per-unit form $V_{LN(\text{pu})}$, or vice versa, we use the formula:

\[V_{LN(\text{pu})} = \cfrac{\sqrt{3}V_{LN(\text{si})}}{V_{LL(\text{b})}}.\]

Info

Similarly to power, JuliaGrid simulations use a single-phase equivalent. Voltage values specified in volts correspond to line-to-neutral values, while base voltages are expected to be provided as line-to-line values.


Impedances

Let us first consider the line itself, excluding transformers. The base impedance of the line is given by:

\[Z_{L(\text{b})} = \cfrac{V_{LL(\text{b})}^2}{S_{3\phi(\text{b})}}.\]

If the impedance is provided in ohms, its value in the per-unit system is:

\[Z_{L(\text{pu})} = \cfrac{Z_{L(\text{si})}}{Z_{L(\text{b})}} = \cfrac{Z_{L(\text{si})} S_{3\phi(\text{b})}}{V_{LL(\text{b})}^2}.\]

A common question that arises is which base voltage should be used for the line, considering the two ends of the line (from-bus and to-bus). The key assumption here is that the base voltages correspond to the nominal voltages of the transformers. Therefore, when the user defines base voltages, JuliaGrid assumes these voltages represent the nominal voltages of the transformers, implying that the base voltages on both the from-bus and to-bus ends of the line will be the same.

Now, let us consider the transformer. The base voltages at the from-bus end (primary side) $V_{LLF(\text{b})}$, and the to-bus end (secondary side) $V_{LLT(\text{b})}$, will generally be different. This requires us to define a conversion method for impedance. Typically, when impedance is given in ohms, it refers to the primary side of the transformer, denoted as $Z_{F(\text{si})}$, while the impedance in our unified branch model refers to the secondary side, denoted as $Z_{T(\text{si})}$. To convert the impedance from the from-bus end to the to-bus end, we use:

\[Z_{T(\text{si})} = \cfrac{Z_{F(\text{si})}}{m^2},\]

where $m$ is the effective turns ratio, calculated as:

\[m = \tau \cfrac{V_{LLF(\text{b})}}{V_{LLT(\text{b})}},\]

with $\tau$ is off-nominal turns ratio. This equation provides the impedance on the to-bus end of the branch or the secondary side of the transformer in ohms.

To convert this impedance to the per-unit system, we use the base impedance for the secondary side:

\[Z_{T(\text{pu})} = \cfrac{Z_{T(\text{si})}}{Z_{T(\text{b})}},\]

where:

\[Z_{T(\text{b})} = \cfrac{V_{LLT(\text{b})}^2}{S_{3\phi(\text{b})}}.\]

Substituting the previous expressions, we obtain the following formula for the impedance on the secondary side in per-unit system:

\[Z_{T(\text{pu})} = \cfrac{Z_{F(\text{si})} S_{3\phi(\text{b})}}{\tau^2 V_{LLF(\text{b})}^2}.\]

This formula applies to both lines and transformers. For a line, where $\tau = 1$, the formula simplifies and becomes the same as the impedance equation for a line.

Info

In the case of a transformer, if impedances or admittances are provided in SI units, they must be specified for the primary side (from-bus end).


Currents

Once the base power and base voltage values are set, we can calculate the base current flowing through a line or branch as follows:

\[I_{L(\text{b})} = \cfrac{S_{3\phi(\text{b})}}{\sqrt{3}V_{LL(\text{b})}}.\]

When we transform currents that are given in SI unit to per-unit, or vice versa, we use the following formula:

\[I_{L(\text{pu})} = \cfrac{I_{L(\text{si})}}{I_{L(\text{b})}} = \cfrac{\sqrt{3}I_{L(\text{si})}V_{LL(\text{b})}}{S_{3\phi(\text{b})}}.\]

+Per-Unit System · JuliaGrid

Per-Unit System

In power system modeling and analysis, variables and parameters are often normalized using the per-unit system. The per-unit system is particularly advantageous for analyzing networks with multiple voltage levels connected by transformers with different turns ratios.

In static scenarios, there are four key quantities of interest: voltage, current, power, and impedance or admittance. Defining a per-unit system requires selecting base values for each of these quantities. However, since these quantities are interconnected by various laws, the choice of base values cannot be arbitrary. Typically, the base quantities are chosen as voltage and power, with the base current and impedance (or admittance) then calculated accordingly. Usually, base quantities are selected as follows:

  • three-phase apparent power $S_{3\phi(\text{b})}$,
  • line-to-line voltage $V_{LL(\text{b})}$.

While the value of three-phase apparent power is unique across the entire system, multiple line-to-line base voltages are used to account for the different voltage zones created by transformers.

Info

Since balanced three-phase power systems are treated as a single line with a neutral return, confusion may arise regarding the relationship between the per-unit values of line voltages and phase voltages, as well as between the per-unit values of single-phase and three-phase powers [7]. To clarify these relationships, we will systematically explore the conversions between the per-unit and SI systems below.


Powers

Let us consider the three-phase apparent power expressed in SI units, denoted as $S_{3\phi(\text{si})}$. To convert this into the per-unit system, we divide it by the base power:

\[S_{3\phi(\text{pu})} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}}.\]

Now, let us examine the power of a single phase and convert it to the per-unit system:

\[S_{1\phi(\text{pu})} = \cfrac{S_{1\phi(\text{si})}}{S_{1\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{3} \cfrac{3}{S_{3\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}} = S_{3\phi(\text{pu})}.\]

This indicates that in the per-unit system, there is no distinction between three-phase and single-phase powers. The type of power only becomes relevant when converting back from per-unit to SI units, and vice versa.

Info

As is standard practice, even if all simulations utilize a single-phase equivalent, input powers provided in SI units are assumed to represent three-phase powers. Similarly, if simulation results are displayed in SI units, they are considered to be three-phase powers, as we have selected three-phase power as the base value.


Voltages

Format for input data that JuliaGrid uses required value for base voltage per each bus, and those values represent the line-to-line voltages. On the other hand, in all analyses we are working with line-to-neutral voltages. To convert a line-to-neutral voltage given in SI units $V_{LN(\text{si})}$ to per-unit form $V_{LN(\text{pu})}$, or vice versa, we use the formula:

\[V_{LN(\text{pu})} = \cfrac{\sqrt{3}V_{LN(\text{si})}}{V_{LL(\text{b})}}.\]

Info

Similarly to power, JuliaGrid simulations use a single-phase equivalent. Voltage values specified in volts correspond to line-to-neutral values, while base voltages are expected to be provided as line-to-line values.


Impedances

Let us first consider the line itself, excluding transformers. The base impedance of the line is given by:

\[Z_{L(\text{b})} = \cfrac{V_{LL(\text{b})}^2}{S_{3\phi(\text{b})}}.\]

If the impedance is provided in ohms, its value in the per-unit system is:

\[Z_{L(\text{pu})} = \cfrac{Z_{L(\text{si})}}{Z_{L(\text{b})}} = \cfrac{Z_{L(\text{si})} S_{3\phi(\text{b})}}{V_{LL(\text{b})}^2}.\]

A common question that arises is which base voltage should be used for the line, considering the two ends of the line (from-bus and to-bus). The key assumption here is that the base voltages correspond to the nominal voltages of the transformers. Therefore, when the user defines base voltages, JuliaGrid assumes these voltages represent the nominal voltages of the transformers, implying that the base voltages on both the from-bus and to-bus ends of the line will be the same.

Now, let us consider the transformer. The base voltages at the from-bus end (primary side) $V_{LLF(\text{b})}$, and the to-bus end (secondary side) $V_{LLT(\text{b})}$, will generally be different. This requires us to define a conversion method for impedance. Typically, when impedance is given in ohms, it refers to the primary side of the transformer, denoted as $Z_{F(\text{si})}$, while the impedance in our unified branch model refers to the secondary side, denoted as $Z_{T(\text{si})}$. To convert the impedance from the from-bus end to the to-bus end, we use:

\[Z_{T(\text{si})} = \cfrac{Z_{F(\text{si})}}{m^2},\]

where $m$ is the effective turns ratio, calculated as:

\[m = \tau \cfrac{V_{LLF(\text{b})}}{V_{LLT(\text{b})}},\]

with $\tau$ is off-nominal turns ratio. This equation provides the impedance on the to-bus end of the branch or the secondary side of the transformer in ohms.

To convert this impedance to the per-unit system, we use the base impedance for the secondary side:

\[Z_{T(\text{pu})} = \cfrac{Z_{T(\text{si})}}{Z_{T(\text{b})}},\]

where:

\[Z_{T(\text{b})} = \cfrac{V_{LLT(\text{b})}^2}{S_{3\phi(\text{b})}}.\]

Substituting the previous expressions, we obtain the following formula for the impedance on the secondary side in per-unit system:

\[Z_{T(\text{pu})} = \cfrac{Z_{F(\text{si})} S_{3\phi(\text{b})}}{\tau^2 V_{LLF(\text{b})}^2}.\]

This formula applies to both lines and transformers. For a line, where $\tau = 1$, the formula simplifies and becomes the same as the impedance equation for a line.

Info

In the case of a transformer, if impedances or admittances are provided in SI units, they must be specified for the primary side (from-bus end).


Currents

Once the base power and base voltage values are set, we can calculate the base current flowing through a line or branch as follows:

\[I_{L(\text{b})} = \cfrac{S_{3\phi(\text{b})}}{\sqrt{3}V_{LL(\text{b})}}.\]

When we transform currents that are given in SI unit to per-unit, or vice versa, we use the following formula:

\[I_{L(\text{pu})} = \cfrac{I_{L(\text{si})}}{I_{L(\text{b})}} = \cfrac{\sqrt{3}I_{L(\text{si})}V_{LL(\text{b})}}{S_{3\phi(\text{b})}}.\]

diff --git a/dev/tutorials/pmuStateEstimation/index.html b/dev/tutorials/pmuStateEstimation/index.html index ad727e56..0872eaa5 100644 --- a/dev/tutorials/pmuStateEstimation/index.html +++ b/dev/tutorials/pmuStateEstimation/index.html @@ -286,4 +286,4 @@ 0.2850121792157389
julia> 𝛙ₗ = analysis.current.series.angle3-element Vector{Float64}: -0.75841409129973 -0.7631714293392173 - 0.31577645020972367 + 0.31577645020972367 diff --git a/dev/tutorials/powerSystemModel/index.html b/dev/tutorials/powerSystemModel/index.html index 96ae6b05..53c78b23 100644 --- a/dev/tutorials/powerSystemModel/index.html +++ b/dev/tutorials/powerSystemModel/index.html @@ -201,4 +201,4 @@ \end{aligned}\]

The sparse nodal matrix $\mathbf{B}$ is stored in the dc field, and we can access it using:

julia> 𝐁 = system.model.dc.nodalMatrix3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries:
   16.6667  -16.6667     ⋅
  -16.6667   21.5258   -4.85909
-    ⋅       -4.85909   4.85909

Bus Injection

From the previous analysis, the calculation of active power injection at each bus is expressed by:

\[ P_i = \sum_{j = 1}^n {B}_{ij} \theta_j + P_{\text{tr}i} + P_{\text{sh}i}, \;\;\; i \in \mathcal{N}.\]

+ ⋅ -4.85909 4.85909
Bus Injection

From the previous analysis, the calculation of active power injection at each bus is expressed by:

\[ P_i = \sum_{j = 1}^n {B}_{ij} \theta_j + P_{\text{tr}i} + P_{\text{sh}i}, \;\;\; i \in \mathcal{N}.\]