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

Feature / Binary search in Automatic Tap Changer #668

Merged
merged 59 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
699f8a9
branch init
Jerry-Jinfeng-Guo Jul 9, 2024
29ee28d
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 9, 2024
d6e362f
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 11, 2024
1e81cd4
added `fast_any`
Jerry-Jinfeng-Guo Jul 11, 2024
2608b23
[skip ci] intermediate commit
Jerry-Jinfeng-Guo Jul 11, 2024
4d0b142
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 11, 2024
8b942fb
[skip ci] added binary search members
Jerry-Jinfeng-Guo Jul 12, 2024
623f6a4
minor clean
Jerry-Jinfeng-Guo Jul 13, 2024
69dc30f
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 22, 2024
51392aa
basic logic in place
Jerry-Jinfeng-Guo Jul 22, 2024
e8a5315
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 22, 2024
096ab0f
clean up
Jerry-Jinfeng-Guo Jul 22, 2024
cd59565
compiler complains
Jerry-Jinfeng-Guo Jul 22, 2024
90e6b1d
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 23, 2024
bed2dff
[skip ci] binary search logic moved away from wrapper; debugging
Jerry-Jinfeng-Guo Jul 23, 2024
5353991
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Jul 23, 2024
6472cd1
1 werror fix
Jerry-Jinfeng-Guo Jul 23, 2024
56a8c0e
3 more werror
Jerry-Jinfeng-Guo Jul 23, 2024
a0319be
[skip ci] wip
Jerry-Jinfeng-Guo Jul 24, 2024
dabd3e1
single transformer finished; TODO pack the indices for the binary_sea…
Jerry-Jinfeng-Guo Jul 25, 2024
663de80
binary search implementation + tests done; next to add a benchmark un…
Jerry-Jinfeng-Guo Jul 25, 2024
b5ce206
cleaned up a bit
Jerry-Jinfeng-Guo Jul 25, 2024
8c3d25d
sonar cloud
Jerry-Jinfeng-Guo Jul 25, 2024
8e91795
addressing comments; debugging validation tests
Jerry-Jinfeng-Guo Jul 26, 2024
81507d3
format
Jerry-Jinfeng-Guo Jul 26, 2024
1d48228
intermediate commit debugging batch validation
Jerry-Jinfeng-Guo Jul 26, 2024
c775dd8
code refactored; validation tests fixed;
Jerry-Jinfeng-Guo Jul 27, 2024
8d4bf5c
clang-tidy
Jerry-Jinfeng-Guo Jul 27, 2024
55df84b
resolve code smells
Jerry-Jinfeng-Guo Jul 28, 2024
37e5784
clang tidy
Jerry-Jinfeng-Guo Jul 28, 2024
a21c62a
unit test for number of pf runs binary search vs scan-line
Jerry-Jinfeng-Guo Jul 28, 2024
ee07a29
format
Jerry-Jinfeng-Guo Jul 28, 2024
6c0282c
one last sonar cloud code smell
Jerry-Jinfeng-Guo Jul 29, 2024
5f7876b
Sonar Cloud, attempt 2.0
Jerry-Jinfeng-Guo Jul 29, 2024
b7647d6
give up on Sonar
Jerry-Jinfeng-Guo Jul 29, 2024
6ee24b2
address most of the comments;
Jerry-Jinfeng-Guo Jul 30, 2024
cccc2ac
added enum and related interface logic
Jerry-Jinfeng-Guo Jul 31, 2024
31bad9c
fixed batch mode error; fixed c api test error
Jerry-Jinfeng-Guo Jul 31, 2024
a50c7f7
doc; TODO: python validation test don't know the error yet
Jerry-Jinfeng-Guo Jul 31, 2024
4689516
address comment and fix python side
Jerry-Jinfeng-Guo Aug 1, 2024
27db414
sonar clouds; few depth warnings are ignored
Jerry-Jinfeng-Guo Aug 1, 2024
5f786a6
sonar clouds, 2.0
Jerry-Jinfeng-Guo Aug 1, 2024
f87da45
sonar cloud 2.1
Jerry-Jinfeng-Guo Aug 1, 2024
68af3ff
make `fast_any` default; updated code and doc
Jerry-Jinfeng-Guo Aug 1, 2024
fca830e
addressed comments
Jerry-Jinfeng-Guo Aug 2, 2024
220801f
sonar clownd
Jerry-Jinfeng-Guo Aug 2, 2024
bbb51ab
addressed comments
Jerry-Jinfeng-Guo Aug 2, 2024
ba8da6e
removed SearchMethod from python enum; optimizer now assigns search m…
Jerry-Jinfeng-Guo Aug 2, 2024
270b5d5
revert changes written to the notebook
Jerry-Jinfeng-Guo Aug 2, 2024
664796a
clang-tidy
Jerry-Jinfeng-Guo Aug 2, 2024
caeee05
resolved one code smell
Jerry-Jinfeng-Guo Aug 2, 2024
612dd8c
docs.
Jerry-Jinfeng-Guo Aug 2, 2024
4781c39
addressing most of the comments from 05-aug
Jerry-Jinfeng-Guo Aug 5, 2024
a930bc0
[skip ci] included the other proposed comment
Jerry-Jinfeng-Guo Aug 5, 2024
7aa5bc4
addressing final comments from 05-aug
Jerry-Jinfeng-Guo Aug 5, 2024
14c4606
Merge branch 'main' into feature/binary-search-tap-changer
Jerry-Jinfeng-Guo Aug 5, 2024
3df1cf3
fotmat
Jerry-Jinfeng-Guo Aug 5, 2024
3ed8aed
unused import
Jerry-Jinfeng-Guo Aug 5, 2024
4674159
updated the notebook and part of the code.
Jerry-Jinfeng-Guo Aug 6, 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
33 changes: 22 additions & 11 deletions docs/user_manual/calculations.md
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,13 @@ These {hoverxreftooltip}`user_manual/components:Transformer Tap Regulator`s try
The $U_{\text{control}}$ may be compensated for the voltage drop during transport.
Power flow calculations that take the behavior of these regulators into account may be toggled by providing one of the following strategies to the {py:meth}`tap_changing_strategy <power_grid_model.PowerGridModel.calculate_power_flow>` option.

| Algorithm | Default | Speed | Algorithm call |
| ---------------------------------------------------------------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| No automatic tap changing (regular power flow) | &#10004; | &#10004; | {py:class}`TapChangingStrategy.disabled <power_grid_model.enum.TapChangingStrategy.disabled>` |
| Optimize tap positions for any value in the voltage band | | &#10004; | {py:class}`TapChangingStrategy.any_valid_tap <power_grid_model.enum.TapChangingStrategy.any_valid_tap>` |
| Optimize tap positions for lowest possible voltage in the voltage band | | | {py:class}`TapChangingStrategy.min_voltage_tap <power_grid_model.enum.TapChangingStrategy.min_voltage_tap>` |
| Optimize tap positions for lowest possible voltage in the voltage band | | | {py:class}`TapChangingStrategy.max_voltage_tap <power_grid_model.enum.TapChangingStrategy.max_voltage_tap>` |
| Algorithm | Default | Speed | Algorithm call |
| --------------------------------------------------------------------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| No automatic tap changing (regular power flow) | &#10004; | &#10004; | {py:class}`TapChangingStrategy.disabled <power_grid_model.enum.TapChangingStrategy.disabled>` |
| Optimize tap positions for any value in the voltage band | | &#10004; | {py:class}`TapChangingStrategy.any_valid_tap <power_grid_model.enum.TapChangingStrategy.any_valid_tap>` |
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved
| Optimize tap positions for lowest possible voltage in the voltage band | | | {py:class}`TapChangingStrategy.min_voltage_tap <power_grid_model.enum.TapChangingStrategy.min_voltage_tap>` |
| Optimize tap positions for lowest possible voltage in the voltage band | | | {py:class}`TapChangingStrategy.max_voltage_tap <power_grid_model.enum.TapChangingStrategy.max_voltage_tap>` |
| Optimize tap positions for any value in the voltage band with binary search | | &#10004; | {py:class}`TapChangingStrategy.fast_any_tap <power_grid_model.enum.TapChangingStrategy.fast_any_tap>` |

##### Control logic for power flow with automatic tap changing

Expand Down Expand Up @@ -647,11 +648,21 @@ Hence, this assumption is reflected in the requirements mentioned in {hoverxreft

Internally, to achieve an optimal regulated tap position, the control algorithm sets initial tap positions and exploits neighborhoods around local optima, depending on the strategy as follows.

| strategy | initial tap position | exploitation direction | description |
| ----------------------------------------------------------------------------------------------------------- | -------------------- | ---------------------- | ------------------------------------------------------------------------------------- |
| {py:class}`TapChangingStrategy.any_valid_tap <power_grid_model.enum.TapChangingStrategy.any_valid_tap>` | current tap position | no exploitation | Find any tap position that gives a control side voltage within the `u_band` |
| {py:class}`TapChangingStrategy.min_voltage_tap <power_grid_model.enum.TapChangingStrategy.min_voltage_tap>` | `tap_max` | step up | Find the tap position that gives the lowest control side voltage within the `u_band` |
| {py:class}`TapChangingStrategy.max_voltage_tap <power_grid_model.enum.TapChangingStrategy.max_voltage_tap>` | `tap_min` | step down | Find the tap position that gives the highest control side voltage within the `u_band` |
| strategy | initial tap position | exploitation direction | search method | description |
| ----------------------------------------------------------------------------------------------------------- | -------------------- | ---------------------- | ------------- | ------------------------------------------------------------------------------------- |
| {py:class}`TapChangingStrategy.any_valid_tap <power_grid_model.enum.TapChangingStrategy.any_valid_tap>` | current tap position | no exploitation | linear_search | Find any tap position that gives a control side voltage within the `u_band` |
| {py:class}`TapChangingStrategy.min_voltage_tap <power_grid_model.enum.TapChangingStrategy.min_voltage_tap>` | `tap_max` | step up | binary_search | Find the tap position that gives the lowest control side voltage within the `u_band` |
| {py:class}`TapChangingStrategy.max_voltage_tap <power_grid_model.enum.TapChangingStrategy.max_voltage_tap>` | `tap_min` | step down | binary_search | Find the tap position that gives the highest control side voltage within the `u_band` |
| {py:class}`TapChangingStrategy.fast_any_tap <power_grid_model.enum.TapChangingStrategy.fast_any_tap>` | current tap position | no exploitation | binary_search | Find any tap position that gives a control side voltage within the `u_band` |
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved

##### Search methods used for tap changing optimization

Given the discrete nature of the finite tap ranges, we use the following search methods to find the next tap position along the exploitation direction.

| Search method | Description |
| ------------- | -------------------------------------------------------------------------------------- |
| linear search | In the context of finite discrete range search, go one value at a time. |
| binary search | In the context of finite discrete range search, go half the remaining range at a time. |
Jerry-Jinfeng-Guo marked this conversation as resolved.
Show resolved Hide resolved


## Batch Calculations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ using IntS = int8_t;
// struct of indexing to sub modules
struct Idx2D {
Idx group; // sequence number of outer module/groups
Idx pos; // sequence number inside the group
Idx pos; // sequence number inside the group
mgovers marked this conversation as resolved.
Show resolved Hide resolved

friend constexpr bool operator==(Idx2D x, Idx2D y) = default;
};

struct Idx2Du {
size_t x;
size_t y;
};

struct Idx2DHash {
std::size_t operator()(const Idx2D& idx) const {
size_t const h1 = std::hash<Idx>{}(idx.group);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ enum class OptimizerStrategy : IntS { // Conventions for optimization strategies
global_maximum = 2, // global_maximum = argmax{f(x) \in Range} for x in Domain
local_minimum = 3, // local_minimum = Any{argmin{f(x) \in Range}} for x in Domain
local_maximum = 4, // local_maximum = Any{argmax{f(x) \in Range}} for x in Domain
fast_any = 5, // fast_any = Any{f(x) \in Range} for x \in Domain, but faster
};

enum class SearchMethod : IntS { // Which type of tap search method for finite element optimization process
linear_search = 0, // use linear_search method: one step per iteration
binary_search = 1, // use binary search: half a tap range at a time
};

} // namespace power_grid_model
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,13 @@ class UnreachableHit : public PowerGridError {
}
};

class TapSearchStrategyIncompatibleError : public InvalidArguments {
public:
template <typename T1, typename T2>
TapSearchStrategyIncompatibleError(std::string const& method, const T1& value1, const T2& value2)
: InvalidArguments{
method, std::string{typeid(T1).name()} + " #" + detail::to_string(static_cast<IntS>(value1)) + " and " +
std::string{typeid(T2).name()} + " #" + detail::to_string(static_cast<IntS>(value2))} {}
};

} // namespace power_grid_model
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ struct MainModelOptions {

CalculationMethod calculation_method{CalculationMethod::default_method};
OptimizerType optimizer_type{OptimizerType::no_optimization};
OptimizerStrategy optimizer_strategy{OptimizerStrategy::any};
OptimizerStrategy optimizer_strategy{OptimizerStrategy::fast_any};
SearchMethod search_method{SearchMethod::binary_search};

double err_tol{1e-8};
Idx max_iter{20};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ class MainModelImpl<ExtraRetrievableTypes<ExtraRetrievableType...>, ComponentLis
options.optimizer_type, options.optimizer_strategy,
calculate_power_flow_<sym>(options.err_tol, options.max_iter),
[this](ConstDataset update_data) { this->update_component<permanent_update_t>(update_data); },
*meta_data_)
*meta_data_, options.search_method)
->optimize(state_, options.calculation_method);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ template <typename State, typename UpdateType, typename StateCalculator, typenam
requires detail::state_calculator_c<StateCalculator, State> &&
std::invocable<std::remove_cvref_t<StateUpdater>, UpdateType>
constexpr auto get_optimizer(OptimizerType optimizer_type, OptimizerStrategy strategy, StateCalculator calculator,
StateUpdater updater, meta_data::MetaData const& meta_data) {
StateUpdater updater, meta_data::MetaData const& meta_data,
SearchMethod search = SearchMethod::binary_search) {
using enum OptimizerType;
using namespace std::string_literals;
using BaseOptimizer = detail::BaseOptimizer<StateCalculator, State>;
Expand All @@ -31,7 +32,7 @@ constexpr auto get_optimizer(OptimizerType optimizer_type, OptimizerStrategy str
std::invocable<std::remove_cvref_t<StateUpdater>, ConstDataset const&> &&
main_core::component_container_c<typename State::ComponentContainer, TransformerTapRegulator>) {
return BaseOptimizer::template make_shared<TapPositionOptimizer<StateCalculator, StateUpdater, State>>(
std::move(calculator), std::move(updater), strategy, meta_data);
std::move(calculator), std::move(updater), strategy, meta_data, search);
}
[[fallthrough]];
default:
Expand Down
Loading