Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Area Interchange Control as OuterLoop #1055

Merged
merged 106 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
08e2260
Add new OLF parameter to enable area interchange control
m-guibert Jul 1, 2024
b7e37e6
Add new OLF parameter to select the areaType used for Area Interchang…
vmouradian Jul 8, 2024
1c2dc4c
finish adding af the 2 new Control Area parameters
vmouradian Jul 12, 2024
c41efe6
add areaInterchangeControlAreaType to LfNetworkParameters
vmouradian Jul 12, 2024
a44d4f0
Initiate LfControlArea interface and impl + add to LfNetwork
vmouradian Jul 12, 2024
f30d7f7
Load Areas to lfNetwork in LfNetworkLoader
vmouradian Jul 12, 2024
5a5a00d
(wip) Unit test
vmouradian Jul 12, 2024
10bf131
change methods order in LfControlArea
vmouradian Jul 17, 2024
04dedf3
replace Evaluable by supplier in ControlArea boundaries
vmouradian Jul 17, 2024
bfc656a
LfNetworkLoader unit test
vmouradian Jul 17, 2024
1929b57
Merge branch 'main' into area_interchange_control_outerloop
vmouradian Jul 18, 2024
63eb397
rename
vmouradian Jul 18, 2024
743827b
rename LfcontrolArea to LfArea + move new parameters to bottom
vmouradian Jul 18, 2024
60adb95
rename
vmouradian Jul 18, 2024
097d801
clarify areas conversion in LfNetworkLoader
vmouradian Jul 18, 2024
5a29ee9
rename + clean
vmouradian Jul 19, 2024
42bfe28
(wip) Area Interchange Control outerloop first version
vmouradian Jul 22, 2024
ba86476
update behaviour in case of failed distribution
vmouradian Jul 22, 2024
5df88b2
style fix
vmouradian Jul 22, 2024
050514c
power distribution fail handled per Area
vmouradian Jul 23, 2024
bdf6261
add unit tests
vmouradian Jul 23, 2024
6a24636
update unit tests
vmouradian Jul 24, 2024
1b27134
add AreaInterchangeControl to LfNetworkParameters
vmouradian Jul 24, 2024
82dddbc
Load areas to LfNetwork only if AreaInterchangeControl is true
vmouradian Jul 24, 2024
d7456e7
Fix copyrights and javadoc
vmouradian Jul 25, 2024
e107aac
Improve logging and reports
vmouradian Jul 25, 2024
ad6a151
fix wrong slack injection computation
vmouradian Jul 25, 2024
05c9a97
improve comment
vmouradian Jul 25, 2024
b5fefc8
fix error message and unit test
vmouradian Jul 25, 2024
f3930a8
check buses with no areas and handle slack on boundary buses
vmouradian Jul 25, 2024
f8142ae
check areas duplicated over multiple LfNetworks
vmouradian Jul 26, 2024
a0d05fb
update unit tests
vmouradian Jul 26, 2024
a7c6a58
clean OpenLoadFlowParameters
jeandemanged Jul 29, 2024
995a1b4
fix
jeandemanged Jul 29, 2024
e83f8af
rename AreaInterchangeControlTest
vmouradian Aug 2, 2024
ccdd43d
fix logger
vmouradian Aug 2, 2024
7294008
add Area interchange control creation to ExplicitAcOuterLoopConfig
vmouradian Aug 2, 2024
c2f88b5
add setter for LfArea interchange target
vmouradian Aug 2, 2024
9a9478c
refactor Areas creation and slack handling in area interchange contro…
vmouradian Aug 2, 2024
8c0fc11
fix
vmouradian Aug 26, 2024
341a8de
remove unused slackBusCount attribute
vmouradian Aug 26, 2024
365e12a
add onAreaAdded post processor
vmouradian Aug 26, 2024
164e899
delete duplicated areas test, replace with testing that all boundarie…
vmouradian Aug 26, 2024
e8257b4
fix aic reports + add unit test
vmouradian Aug 26, 2024
66b0478
doc v1
vmouradian Aug 26, 2024
da68498
doc v2
vmouradian Aug 26, 2024
eea4667
fix Q state update
vmouradian Aug 28, 2024
672b513
Merge branch 'main' into area_interchange_control_outerloop
vmouradian Aug 28, 2024
a5c7e25
clean
vmouradian Aug 28, 2024
a49dc24
fix precision
vmouradian Sep 4, 2024
cdf29bb
fix np errors with tielines
vmouradian Sep 4, 2024
59bd9dc
handle networks with no-Area parts and Networks with fragmented areas
vmouradian Sep 5, 2024
f340a65
remove dead code
vmouradian Sep 5, 2024
dae8119
rename, clarify, comment, clean
vmouradian Sep 9, 2024
7818836
refactor + clean
vmouradian Sep 12, 2024
a8a72fe
Merge branch 'main' into area_interchange_control_outerloop
vmouradian Sep 12, 2024
5c90423
find reference generator before using activepower distribution
vmouradian Sep 13, 2024
160838a
Merge branch 'main' into area_interchange_control_outerloop
jeandemanged Sep 18, 2024
ea25fef
sonar fix
jeandemanged Sep 18, 2024
7f2784e
wip
jeandemanged Sep 19, 2024
71f2ee5
fix
jeandemanged Sep 19, 2024
48e3811
fix
jeandemanged Sep 19, 2024
a39a033
fix distribution on conform loads
jeandemanged Sep 19, 2024
89b7b51
clean now useless method
jeandemanged Sep 19, 2024
332a3a3
don't consider fictitious buses as buses without areas
jeandemanged Sep 19, 2024
60c1277
wip
vmouradian Sep 19, 2024
324f287
Omptimize ditribution
vmouradian Sep 20, 2024
e8becbc
Handle disabled branches in LfAreaImpl.BoundaryImpl::getP
m-guibert Sep 24, 2024
6b555c8
Fix : take absolute value for test on slack
vmouradian Sep 25, 2024
8446265
add support AIC for sensi analysis + unit test
vmouradian Sep 25, 2024
f4f1e10
Compatibility of AIC for SA
vmouradian Sep 25, 2024
769c7ad
checks on optional
vmouradian Sep 26, 2024
3b34e72
remove useless checks
vmouradian Sep 26, 2024
f7cb4b4
Stop splitting tielines into 2 dangling lines
vmouradian Sep 27, 2024
2d0a1ca
unit tests for fragmented Areas
vmouradian Sep 27, 2024
2982e8a
checkstyle
vmouradian Sep 27, 2024
272f973
clean
vmouradian Sep 27, 2024
ff97ea8
Merge branch 'main' into area_interchange_control_outerloop
jeandemanged Sep 30, 2024
0c081f7
clean
jeandemanged Sep 30, 2024
0c83eb2
fix
jeandemanged Sep 30, 2024
846610f
Enhance doc
vmouradian Sep 30, 2024
7f7e218
Fix : invalid areas
vmouradian Sep 30, 2024
156f309
checkstyle
vmouradian Sep 30, 2024
73bc0d0
fix doc
vmouradian Sep 30, 2024
8d9ddee
remove reference generator selection for areas active power distrib
vmouradian Oct 2, 2024
e5d9d8d
typo
vmouradian Oct 3, 2024
6cc333a
fix area interchange control and distributed slack outer loops creation
vmouradian Oct 3, 2024
5a77807
update unit test for slack distrib outer loops
vmouradian Oct 4, 2024
6e74727
default to distributed slack outerloop if no areas
vmouradian Oct 4, 2024
a2259bc
add areainterchangePMaxMismatch parameter
vmouradian Oct 4, 2024
f915929
fix imports
vmouradian Oct 4, 2024
7cff6a8
replace getAreas by getAreasStream and hasArea
vmouradian Oct 4, 2024
50178e6
clarify fragmented areas check and logging
vmouradian Oct 4, 2024
ae3a8ef
doc review & increase interchange max mismatch default to 2 MW
jeandemanged Oct 7, 2024
eccd039
Merge branch 'main' into area_interchange_control_outerloop
jeandemanged Oct 7, 2024
7ac63b6
LfNetworkLoaderImpl warning logs consistency
jeandemanged Oct 7, 2024
fe27a4e
clean
jeandemanged Oct 7, 2024
5ee68b6
clean reports, keep them structured - do not report hardcoded formatt…
jeandemanged Oct 7, 2024
fd5e6bd
Merge branch 'refs/heads/main' into area_interchange_control_outerloop
jeandemanged Oct 7, 2024
33be2b8
fix mismatch report typed value
jeandemanged Oct 7, 2024
9480e94
Add reports about area validation
jeandemanged Oct 7, 2024
23b8c97
fix report pu vs MW
jeandemanged Oct 7, 2024
be6b7c3
fix doc
jeandemanged Oct 8, 2024
99a8774
Merge branch 'refs/heads/main' into area_interchange_control_outerloop
jeandemanged Oct 8, 2024
8f91655
Fix tieline boundary flow considering split shunt admittance of dangl…
jeandemanged Oct 8, 2024
f7182d2
fix log message extra $ char
jeandemanged Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions docs/loadflow/loadflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,81 @@ Note that the vector $b$ of right-hand sides is linearly computed from the given

To solve this system, we follow the classic approach of the LU matrices decomposition $J = LU$.
Hence, by solving the system using LU decomposition, you can compute the voltage angles by giving as data the injections and the phase-shifting angles.

## Area Interchange Control

Area Interchange Control consists in having the Load Flow finding a solution where area interchanges are solved to match the input target interchange values.

Currently, Area Interchange Control is only supported for AC load flow, DC load flow support is planned for future release.

The area interchange control feature is optional, can be activated via the [parameter `areaInterchangeControl`](parameters.md)
and is performed by an outer loop.

Area Interchange Control is performed using an outer loop, similar in principle to the traditional `SlackDistribution` outer loop.
However unlike the `SlackDistribution` outer loop which distributes imbalance over the entire synchronous component (island),
the Area Interchange Control outer loop performs an active power distribution over areas
(filtered on areas having their type matching the configured [parameter `areaInterchangeControlAreaType`](parameters.md)),
in order to have all areas' active power interchanges matching their target interchanges.

The Area Interchange Control outer loop can handle networks where part (or even all) of the buses are not in an area.
For networks that have no areas at all, the behaviour is the same as with the distributed slack outer loop - in such case
internally the Area Interchange Control outer loop just triggers the Slack Distribution outer loop logic.

Just like other outer loops, the Area Interchange Control outer loop checks whether area imbalance must be distributed:
* If no, the outer loop is stable
* If yes, the outer loop is unstable and a new Newton-Raphson is triggered

### Area Interchange Control - algorithm description

The active power is distributed separately on injections (as configured in the [parameter `balanceType`](parameters.md)) of each area
to compensate the area "total mismatch" that is given by:

$$
Area Total Mismatch = Interchange - Interchange Target + Slack Injection
$$

Where:
* "Interchange" is the sum of the power flows at the boundaries of the area (load sign convention i.e. counted positive for imports).
* "Interchange Target" is the interchange target parameter of the area.
* "Slack Injection" is the active power mismatch of the slack bus(es) present in the area (see [Slack bus mismatch attribution](#slack-bus-mismatch-attribution)).

The outer loop iterates until this mismatch is below the configured [parameter `areaInterchangePMaxMismatch`](parameters.md) for all areas.

When it is the case, "interchange only" mismatch is computed for all areas:

$$
Interchange Mismatch = Interchange - Interchange Target
$$

If this mismatch for all areas and the slack injection of the buses without area are below the configured [parameter `slackBusPMaxMismatch`](parameters.md)
then the outerloop is stable and declares a stable status, meaning that the interchanges are correct and the slack bus active power is distributed.

If not, the remaining mismatch is first distributed over the buses that have no area.

If some mismatch still remains, it is distributed equally over all the areas.

### Areas validation
There are some cases where areas are considered invalid and will not be considered for the area interchange control:
- Areas without interchange target
- Areas without boundaries
- Areas that have boundaries in multiple synchronous/connected components. If all the boundaries are in the same component but some buses are in different components, only the part in the component of the boundaries will be considered.

In such cases the involved areas are not considered in the Area Interchange Control outer loop, however other valid areas will still be considered.

### Interchange flow calculation

In iIDM each area defines the boundary points to be considered in the interchange. iIDM supports two ways of modeling area boundaries:
- either via an equipment terminal,
- or via a DanglingLine boundary.

In the DanglingLine case, the flow at the boundary side is considered as it should be, for both unpaired DanglingLines and DanglingLines paired in a TieLine.

### Slack bus mismatch attribution
Depending on the location of the slack bus(es), the role of distributing the active power mismatch will be attributed based on the following logic:
- If the slack bus is part of an area: the slack power is attributed to the area (see "total mismatch" calculation in [Algorithm description](#area-interchange-control---algorithm-description)).
Indeed, in this case the slack injection can be seen as an interchange to 'the void' which must be resolved.
- Slack bus has no area:
- Connected to other bus(es) without area: treated as the slack mismatch of the buses without area
- Connected to only buses that have an area:
- All connected branches are boundaries of those areas: Not attributed to anyone, the mismatch will already be present in the interchange mismatch
- Some connected branches are not declared as boundaries of the areas: Amount of mismatch to distribute is split equally among the areas (added to their "total mismatch")
14 changes: 14 additions & 0 deletions docs/loadflow/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@ When slack distribution is enabled (`distributedSlack` set to `true` in LoadFlow
is considered to be distributed.
The default value is `1 MW` and it must be greater or equal to `0 MW`.

**areaInterchangeControl**
The `areaInterchangeControl` property is an optional property that defines if the [area interchange control](loadflow.md#area-interchange-control) outer loop is enabled.
If set to `true`, the area interchange control outer loop will be used instead of the slack distribution outer loop.
The default value is `false`.

**areaInterchangeControlAreaType**
Defines the `areaType` of the areas on which the [area interchange control](loadflow.md#area-interchange-control) is applied.
Only the areas of the input network that have this type will be considered.
The default value is `ControlArea`.

**areaInterchangePMaxMismatch**
Defines the maximum interchange mismatch tolerance for [area interchange control](loadflow.md#area-interchange-control).
The default value is `2 MW` and it must be greater than `0 MW`.

**voltageRemoteControl**
The `voltageRemoteControl` property is an optional property that defines if the remote control for voltage controllers has to be modeled.
If set to false, any existing voltage remote control is converted to a local control, rescaling the target voltage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@
import com.powsybl.openloadflow.ac.outerloop.*;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.util.PerUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Optional;

/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
abstract class AbstractAcOuterLoopConfig implements AcOuterLoopConfig {
jeandemanged marked this conversation as resolved.
Show resolved Hide resolved

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAcOuterLoopConfig.class);

protected AbstractAcOuterLoopConfig() {
}

Expand All @@ -30,6 +35,14 @@ protected static Optional<AcOuterLoop> createDistributedSlackOuterLoop(LoadFlowP
return Optional.empty();
}

protected static Optional<AcOuterLoop> createAreaInterchangeControlOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
if (parametersExt.isAreaInterchangeControl()) {
ActivePowerDistribution activePowerDistribution = ActivePowerDistribution.create(parameters.getBalanceType(), parametersExt.isLoadPowerFactorConstant(), parametersExt.isUseActiveLimits());
return Optional.of(new AreaInterchangeControlOuterloop(activePowerDistribution, parametersExt.getSlackBusPMaxMismatch(), parametersExt.getAreaInterchangePMaxMismatch()));
}
return Optional.empty();
}

protected static Optional<AcOuterLoop> createReactiveLimitsOuterLoop(LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
if (parameters.isUseReactiveLimits()) {
double effectiveMaxReactivePowerMismatch = switch (parametersExt.getNewtonRaphsonStoppingCriteriaType()) {
Expand Down Expand Up @@ -122,4 +135,18 @@ protected static Optional<AcOuterLoop> createAutomationSystemOuterLoop(OpenLoadF
}
return Optional.empty();
}

static List<AcOuterLoop> filterInconsistentOuterLoops(List<AcOuterLoop> outerLoops) {
if (outerLoops.stream().anyMatch(AreaInterchangeControlOuterloop.class::isInstance)) {
return outerLoops.stream().filter(o -> {
if (o instanceof DistributedSlackOuterLoop) {
LOGGER.warn("Distributed slack and area interchange control are both enabled. " +
"Distributed slack outer loop will be disabled, slack will be distributed by the area interchange control.");
return false;
}
return true;
}).toList();
}
return outerLoops;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public List<AcOuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPa
List<AcOuterLoop> outerLoops = new ArrayList<>(5);
// primary frequency control
createDistributedSlackOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
// area interchange control
createAreaInterchangeControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
// secondary voltage control
createSecondaryVoltageControlOuterLoop(parametersExt).ifPresent(outerLoops::add);
// primary voltage control
Expand All @@ -38,6 +40,6 @@ public List<AcOuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPa
createShuntVoltageControlOuterLoop(parameters, parametersExt).ifPresent(outerLoops::add);
// automation system
createAutomationSystemOuterLoop(parametersExt).ifPresent(outerLoops::add);
return outerLoops;
return filterInconsistentOuterLoops(outerLoops);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public class ExplicitAcOuterLoopConfig extends AbstractAcOuterLoopConfig {
SimpleTransformerVoltageControlOuterLoop.NAME,
TransformerVoltageControlOuterLoop.NAME,
AutomationSystemOuterLoop.NAME,
IncrementalTransformerReactivePowerControlOuterLoop.NAME);
IncrementalTransformerReactivePowerControlOuterLoop.NAME,
AreaInterchangeControlOuterloop.NAME);

private static Optional<AcOuterLoop> createOuterLoop(String name, LoadFlowParameters parameters, OpenLoadFlowParameters parametersExt) {
return switch (name) {
Expand Down Expand Up @@ -68,6 +69,7 @@ private static Optional<AcOuterLoop> createOuterLoop(String name, LoadFlowParame
parametersExt.getGeneratorVoltageControlMinNominalVoltage());
case AutomationSystemOuterLoop.NAME -> createAutomationSystemOuterLoop(parametersExt);
case IncrementalTransformerReactivePowerControlOuterLoop.NAME -> createTransformerReactivePowerControlOuterLoop(parametersExt);
case AreaInterchangeControlOuterloop.NAME -> createAreaInterchangeControlOuterLoop(parameters, parametersExt);
default -> throw new PowsyblException("Unknown outer loop '" + name + "'");
};
}
Expand All @@ -89,6 +91,6 @@ public List<AcOuterLoop> configure(LoadFlowParameters parameters, OpenLoadFlowPa
.flatMap(name -> createOuterLoop(name, parameters, parametersExt).stream())
.toList();
checkTypeUnicity(outerLoops);
return outerLoops;
return filterInconsistentOuterLoops(outerLoops);
}
}
Loading