From ec0c082d0356f5f9ee36d4de260ee4aa118274a0 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Wed, 18 Dec 2024 15:54:52 +0100 Subject: [PATCH 1/3] test to fix issue with disconnected slack [skip ci] Signed-off-by: DONNOT Benjamin --- CHANGELOG.rst | 12 ++ docs/conf.py | 2 +- lightsim2grid/__init__.py | 2 +- setup.py | 8 +- src/GridModel.h | 17 +- src/element_container/GeneratorContainer.cpp | 198 ++++++------------- src/element_container/GeneratorContainer.h | 99 ++++------ src/element_container/LoadContainer.cpp | 114 +---------- src/element_container/LoadContainer.h | 100 ++-------- src/element_container/OneSideContainer.cpp | 114 +++++++++++ src/element_container/OneSideContainer.h | 152 ++++++++++++++ src/element_container/SGenContainer.cpp | 129 ++---------- src/element_container/SGenContainer.h | 72 ++----- src/element_container/ShuntContainer.cpp | 103 +--------- src/element_container/ShuntContainer.h | 80 +++----- 15 files changed, 480 insertions(+), 722 deletions(-) create mode 100644 src/element_container/OneSideContainer.cpp create mode 100644 src/element_container/OneSideContainer.h diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f92998c..a38efaa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,9 @@ Change Log - maybe have a look at suitesparse "sliplu" tools ? - easier building (get rid of the "make" part) +TODO: speed directly update the pv, pq, Sbus and Ybus part when updating the elements + (less error prone and faster to recompute). Then what is passed to the solver + is "only" a "mask" of these data when null TODO: https://github.com/haranjackson/NewtonKrylov for another type of algorithm ? TODO HVDC in Jacobian (see pandapower) TODO: in ContingencyAnalysisCpp: add back the `if(!ac_solver_used)` inside the `remove_from_Ybus` @@ -26,6 +29,15 @@ TODO: in `main.cpp` check the returned policy of pybind11 and also the `py::call TODO: a cpp class that is able to compute (DC powerflow) ContingencyAnalysis and TimeSeries using PTDF and LODF TODO: integration test with pandapower (see `pandapower/contingency/contingency.py` and import `lightsim2grid_installed` and check it's True) +[0.10.0.post1] 2024-12-xx +---------------------------- +- [FIXED] an error when changing of bus one of the slack (did not trigger the + recompute of pv bus ids) +- [FIXED] an issue when turning off a generator: it was still declared as "slack" + if it was one. +- [IMPROVED] refactoring of the c++ side container element to reduce + code (for "one end" elements such as loads, generators, static generators and shunts) + [0.10.0] 2024-12-17 ------------------- - [BREAKING] disconnected storage now raises errors if some power is produced / absorbed, when using legacy grid2op version, diff --git a/docs/conf.py b/docs/conf.py index 512eedd..e3d3412 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Benjamin DONNOT' # The full version, including alpha/beta/rc tags -release = "0.10.0" +release = "0.10.0.post1" version = '0.10' # -- General configuration --------------------------------------------------- diff --git a/lightsim2grid/__init__.py b/lightsim2grid/__init__.py index f5c5ccd..7304d62 100644 --- a/lightsim2grid/__init__.py +++ b/lightsim2grid/__init__.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform. -__version__ = "0.10.0" +__version__ = "0.10.0.post1" __all__ = ["newtonpf", "SolverType", "ErrorType", "solver", "compilation_options"] diff --git a/setup.py b/setup.py index 2cff340..17431b9 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from pybind11.setup_helpers import Pybind11Extension, build_ext -__version__ = "0.10.0" +__version__ = "0.10.0.post1" KLU_SOLVER_AVAILABLE = False # Try to link against SuiteSparse (if available) @@ -152,14 +152,16 @@ "src/batch_algorithm/BaseBatchSolverSynch.cpp", "src/batch_algorithm/TimeSeries.cpp", "src/batch_algorithm/ContingencyAnalysis.cpp", - "src/element_container/LineContainer.cpp", "src/element_container/GenericContainer.cpp", + "src/element_container/OneSideContainer.cpp", "src/element_container/ShuntContainer.cpp", "src/element_container/TrafoContainer.cpp", "src/element_container/LoadContainer.cpp", "src/element_container/GeneratorContainer.cpp", "src/element_container/SGenContainer.cpp", - "src/element_container/DCLineContainer.cpp"] + "src/element_container/DCLineContainer.cpp", + "src/element_container/LineContainer.cpp", + ] if KLU_SOLVER_AVAILABLE: src_files.append("src/linear_solvers/KLUSolver.cpp") diff --git a/src/GridModel.h b/src/GridModel.h index e16e829..16a1858 100644 --- a/src/GridModel.h +++ b/src/GridModel.h @@ -452,32 +452,33 @@ class GridModel : public GenericContainer void deactivate_load(int load_id) {loads_.deactivate(load_id, solver_control_); } void reactivate_load(int load_id) {loads_.reactivate(load_id, solver_control_); } void change_bus_load(int load_id, int new_bus_id) {loads_.change_bus(load_id, new_bus_id, solver_control_, static_cast(bus_vn_kv_.size())); } - void change_p_load(int load_id, real_type new_p) {loads_.change_p(load_id, new_p, solver_control_); } - void change_q_load(int load_id, real_type new_q) {loads_.change_q(load_id, new_q, solver_control_); } + void change_p_load(int load_id, real_type new_p) {loads_.change_p_nothrow(load_id, new_p, solver_control_); } + void change_q_load(int load_id, real_type new_q) {loads_.change_q_nothrow(load_id, new_q, solver_control_); } int get_bus_load(int load_id) {return loads_.get_bus(load_id);} //generator void deactivate_gen(int gen_id) {generators_.deactivate(gen_id, solver_control_); } void reactivate_gen(int gen_id) {generators_.reactivate(gen_id, solver_control_); } void change_bus_gen(int gen_id, int new_bus_id) {generators_.change_bus(gen_id, new_bus_id, solver_control_, static_cast(bus_vn_kv_.size())); } - void change_p_gen(int gen_id, real_type new_p) {generators_.change_p(gen_id, new_p, solver_control_); } - void change_v_gen(int gen_id, real_type new_v_pu) {generators_.change_v(gen_id, new_v_pu, solver_control_); } + void change_p_gen(int gen_id, real_type new_p) {generators_.change_p_nothrow(gen_id, new_p, solver_control_); } + void change_q_gen(int gen_id, real_type new_q) {generators_.change_q_nothrow(gen_id, new_q, solver_control_); } + void change_v_gen(int gen_id, real_type new_v_pu) {generators_.change_v_nothrow(gen_id, new_v_pu, solver_control_); } int get_bus_gen(int gen_id) {return generators_.get_bus(gen_id);} //shunt void deactivate_shunt(int shunt_id) {shunts_.deactivate(shunt_id, solver_control_); } void reactivate_shunt(int shunt_id) {shunts_.reactivate(shunt_id, solver_control_); } void change_bus_shunt(int shunt_id, int new_bus_id) {shunts_.change_bus(shunt_id, new_bus_id, solver_control_, static_cast(bus_vn_kv_.size())); } - void change_p_shunt(int shunt_id, real_type new_p) {shunts_.change_p(shunt_id, new_p, solver_control_); } - void change_q_shunt(int shunt_id, real_type new_q) {shunts_.change_q(shunt_id, new_q, solver_control_); } + void change_p_shunt(int shunt_id, real_type new_p) {shunts_.change_p_nothrow(shunt_id, new_p, solver_control_); } + void change_q_shunt(int shunt_id, real_type new_q) {shunts_.change_q_nothrow(shunt_id, new_q, solver_control_); } int get_bus_shunt(int shunt_id) {return shunts_.get_bus(shunt_id);} //static gen void deactivate_sgen(int sgen_id) {sgens_.deactivate(sgen_id, solver_control_); } void reactivate_sgen(int sgen_id) {sgens_.reactivate(sgen_id, solver_control_); } void change_bus_sgen(int sgen_id, int new_bus_id) {sgens_.change_bus(sgen_id, new_bus_id, solver_control_, static_cast(bus_vn_kv_.size())); } - void change_p_sgen(int sgen_id, real_type new_p) {sgens_.change_p(sgen_id, new_p, solver_control_); } - void change_q_sgen(int sgen_id, real_type new_q) {sgens_.change_q(sgen_id, new_q, solver_control_); } + void change_p_sgen(int sgen_id, real_type new_p) {sgens_.change_p_nothrow(sgen_id, new_p, solver_control_); } + void change_q_sgen(int sgen_id, real_type new_q) {sgens_.change_q_nothrow(sgen_id, new_q, solver_control_); } int get_bus_sgen(int sgen_id) {return sgens_.get_bus(sgen_id);} //storage units diff --git a/src/element_container/GeneratorContainer.cpp b/src/element_container/GeneratorContainer.cpp index 38aae59..f8c3b6d 100644 --- a/src/element_container/GeneratorContainer.cpp +++ b/src/element_container/GeneratorContainer.cpp @@ -16,30 +16,37 @@ void GeneratorContainer::init(const RealVect & generators_p, const RealVect & generators_max_q, const Eigen::VectorXi & generators_bus_id) { + const auto generators_q = RealVect::Zero(generators_p.size()); + const auto voltage_regulator_on = std::vector(generators_p.size(), true); + init_full(generators_p, generators_v, generators_q, + voltage_regulator_on, + generators_min_q, generators_max_q, + generators_bus_id); +} + +void GeneratorContainer::init_full(const RealVect & generators_p, + const RealVect & generators_v, + const RealVect & generators_q, + const std::vector & voltage_regulator_on, + const RealVect & generators_min_q, + const RealVect & generators_max_q, + const Eigen::VectorXi & generators_bus_id + ) +{ + OneSideContainer::init_base(generators_p, generators_q, generators_bus_id, "generators"); + + // check the sizes int size = static_cast(generators_p.size()); - GenericContainer::check_size(generators_p, size, "generators_p"); - GenericContainer::check_size(generators_v, size, "generators_v"); - GenericContainer::check_size(generators_min_q, size, "generators_min_q"); - GenericContainer::check_size(generators_max_q, size, "generators_max_q"); - GenericContainer::check_size(generators_bus_id, size, "generators_bus_id"); + check_size(generators_v, size, "generators_v"); + check_size(generators_min_q, size, "generators_min_q"); + check_size(generators_max_q, size, "generators_max_q"); + check_size(voltage_regulator_on, size, "voltage_regulator_on"); - p_mw_ = generators_p; + // fill the data vm_pu_ = generators_v; - bus_id_ = generators_bus_id; min_q_ = generators_min_q; max_q_ = generators_max_q; - if(min_q_.size() != max_q_.size()) - { - std::ostringstream exc_; - exc_ << "GeneratorContainer::init: Impossible to initialize generator with generators_min_q of size "; - exc_ << min_q_.size(); - exc_ << " and generators_max_q of size "; - exc_ << max_q_.size(); - exc_ << ". Both should match"; - throw std::runtime_error(exc_.str()); - } - const int nb_gen = static_cast(min_q_.size()); - for(int gen_id = 0; gen_id < nb_gen; ++gen_id){ + for(int gen_id = 0; gen_id < size; ++gen_id){ if (min_q_(gen_id) > max_q_(gen_id)) { std::ostringstream exc_; @@ -48,78 +55,60 @@ void GeneratorContainer::init(const RealVect & generators_p, throw std::runtime_error(exc_.str()); } } - status_ = std::vector(generators_p.size(), true); gen_slackbus_ = std::vector(generators_p.size(), false); gen_slack_weight_ = std::vector(generators_p.size(), 0.); turnedoff_gen_pv_ = true; - voltage_regulator_on_ = std::vector(generators_p.size(), true); - q_mvar_ = RealVect::Zero(generators_p.size()); - reset_results(); -} - -void GeneratorContainer::init_full(const RealVect & generators_p, - const RealVect & generators_v, - const RealVect & generators_q, - const std::vector & voltage_regulator_on, - const RealVect & generators_min_q, - const RealVect & generators_max_q, - const Eigen::VectorXi & generators_bus_id - ) -{ - init(generators_p, generators_v, generators_min_q, generators_max_q, generators_bus_id); - int size = static_cast(generators_p.size()); - GenericContainer::check_size(generators_q, size, "generators_q"); - GenericContainer::check_size(voltage_regulator_on, size, "voltage_regulator_on"); voltage_regulator_on_ = voltage_regulator_on; - q_mvar_ = generators_q; + reset_results(); } GeneratorContainer::StateRes GeneratorContainer::get_state() const { - std::vector p_mw(p_mw_.begin(), p_mw_.end()); std::vector vm_pu(vm_pu_.begin(), vm_pu_.end()); - std::vector q_mvar(q_mvar_.begin(), q_mvar_.end()); std::vector min_q(min_q_.begin(), min_q_.end()); std::vector max_q(max_q_.begin(), max_q_.end()); - std::vector bus_id(bus_id_.begin(), bus_id_.end()); - std::vector status = status_; std::vector slack_bus = gen_slackbus_; std::vector voltage_regulator_on = voltage_regulator_on_; std::vector slack_weight = gen_slack_weight_; - GeneratorContainer::StateRes res(names_, turnedoff_gen_pv_, voltage_regulator_on, - p_mw, vm_pu, q_mvar, - min_q, max_q, bus_id, status, slack_bus, slack_weight); + GeneratorContainer::StateRes res(OneSideContainer::get_state(), + turnedoff_gen_pv_, + voltage_regulator_on, + vm_pu, + min_q, + max_q, + slack_bus, + slack_weight); return res; } void GeneratorContainer::set_state(GeneratorContainer::StateRes & my_state) { - names_ = std::get<0>(my_state); + OneSideContainer::set_base_state(std::get<0>(my_state)); turnedoff_gen_pv_ = std::get<1>(my_state); // the generators themelves std::vector & voltage_regulator_on = std::get<2>(my_state); - std::vector & p_mw = std::get<3>(my_state); - std::vector & vm_pu = std::get<4>(my_state); - std::vector & q_mvar = std::get<5>(my_state); - std::vector & min_q = std::get<6>(my_state); - std::vector & max_q = std::get<7>(my_state); - std::vector & bus_id = std::get<8>(my_state); - std::vector & status = std::get<9>(my_state); - std::vector & slack_bus = std::get<10>(my_state); - std::vector & slack_weight = std::get<11>(my_state); - // TODO check sizes - - // input data + std::vector & vm_pu = std::get<3>(my_state); + std::vector & min_q = std::get<4>(my_state); + std::vector & max_q = std::get<5>(my_state); + std::vector & slack_bus = std::get<6>(my_state); + std::vector & slack_weight = std::get<7>(my_state); + + // check sizes + const auto size = nb(); + check_size(voltage_regulator_on, size, "voltage_regulator_on"); + check_size(vm_pu, size, "vm_pu"); + check_size(min_q, size, "min_q"); + check_size(max_q, size, "max_q"); + check_size(slack_bus, size, "slack_bus"); + check_size(slack_weight, size, "slack_weight"); + + // assign data voltage_regulator_on_ = voltage_regulator_on; - p_mw_ = RealVect::Map(&p_mw[0], p_mw.size()); vm_pu_ = RealVect::Map(&vm_pu[0], vm_pu.size()); - q_mvar_ = RealVect::Map(&q_mvar[0], q_mvar.size()); min_q_ = RealVect::Map(&min_q[0], min_q.size()); max_q_ = RealVect::Map(&max_q[0], max_q.size()); - bus_id_ = Eigen::VectorXi::Map(&bus_id[0], bus_id.size()); - status_ = status; gen_slackbus_ = slack_bus; gen_slack_weight_ = slack_weight; reset_results(); @@ -224,8 +213,7 @@ void GeneratorContainer::compute_results(const Eigen::Ref & Va, bool ac) { const int nb_gen = nb(); - v_kv_from_vpu(Va, Vm, status_, nb_gen, bus_id_, id_grid_to_solver, bus_vn_kv, res_v_); - v_deg_from_va(Va, Vm, status_, nb_gen, bus_id_, id_grid_to_solver, bus_vn_kv, res_theta_); + OneSideContainer::compute_results_base(Va, Vm, V, id_grid_to_solver, bus_vn_kv, sn_mva, ac); for(int gen_id = 0; gen_id < nb_gen; ++gen_id){ if(!status_[gen_id]){ res_p_(gen_id) = 0.; @@ -235,13 +223,6 @@ void GeneratorContainer::compute_results(const Eigen::Ref & Va, } } -void GeneratorContainer::reset_results(){ - res_p_ = RealVect(nb()); // in MW - res_q_ = RealVect(nb()); // in MVar - res_v_ = RealVect(nb()); // in kV - res_theta_ = RealVect(nb()); // in deg -} - void GeneratorContainer::get_vm_for_dc(RealVect & Vm){ const int nb_gen = nb(); int bus_id_me; @@ -258,18 +239,8 @@ void GeneratorContainer::get_vm_for_dc(RealVect & Vm){ } } -void GeneratorContainer::change_p(int gen_id, real_type new_p, SolverControl & solver_control) +void GeneratorContainer::change_p_nothrow(int gen_id, real_type new_p, SolverControl & solver_control) { - bool my_status = status_.at(gen_id); // and this check that load_id is not out of bound - if(!my_status) - { - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "GeneratorContainer::change_p: Impossible to change the active value of a disconnected generator (check gen. id "; - exc_ << gen_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); - } if(!turnedoff_gen_pv_){ // if turned off generators (including these with p==0) // are not pv, if we change the active generation, it changes @@ -280,44 +251,26 @@ void GeneratorContainer::change_p(int gen_id, real_type new_p, SolverControl & s solver_control.tell_pv_changed(); } } - if (p_mw_(gen_id) != new_p){ - solver_control.tell_recompute_sbus(); - p_mw_(gen_id) = new_p; - } + OneSideContainer::change_p_nothrow(gen_id, new_p, solver_control); } -void GeneratorContainer::change_q(int gen_id, real_type new_q, SolverControl & solver_control) +void GeneratorContainer::change_v(int gen_id, real_type new_v_pu, SolverControl & solver_control) { bool my_status = status_.at(gen_id); // and this check that load_id is not out of bound if(!my_status) { // TODO DEBUG MODE only this in debug mode std::ostringstream exc_; - exc_ << "GeneratorContainer::change_q: Impossible to change the reactive value of a disconnected generator (check gen. id "; + exc_ << "GeneratorContainer::change_p: Impossible to change the voltage setpoint of a disconnected generator (check gen. id "; exc_ << gen_id; exc_ << ")"; throw std::runtime_error(exc_.str()); } - // TODO DEBUG MODE : raise an error if generator is regulating voltage, maybe ? - // this would have not effect - if (q_mvar_(gen_id) != new_q){ - solver_control.tell_recompute_sbus(); - q_mvar_(gen_id) = new_q; - } + change_v_nothrow(gen_id, new_v_pu, solver_control); } -void GeneratorContainer::change_v(int gen_id, real_type new_v_pu, SolverControl & solver_control) +void GeneratorContainer::change_v_nothrow(int gen_id, real_type new_v_pu, SolverControl & solver_control) { - bool my_status = status_.at(gen_id); // and this check that load_id is not out of bound - if(!my_status) - { - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "GeneratorContainer::change_p: Impossible to change the voltage setpoint of a disconnected generator (check gen. id "; - exc_ << gen_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); - } if (vm_pu_(gen_id) != new_v_pu) solver_control.tell_v_changed(); vm_pu_(gen_id) = new_v_pu; } @@ -331,6 +284,8 @@ void GeneratorContainer::set_vm(CplxVect & V, const std::vector & id_grid_t if(!status_[gen_id]) continue; if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv + + // pseudo off generator (with p == 0) bool pseudo_off = p_mw_(gen_id) == 0.; // though "pseudo off" a slack is still "PV" if(gen_slack_weight_[gen_id] != 0.) pseudo_off = false; @@ -498,24 +453,6 @@ void GeneratorContainer::update_slack_weights(Eigen::Ref & bus_status) const { - const int nb_gen = nb(); - for(int gen_id = 0; gen_id < nb_gen; ++gen_id) - { - if(!status_[gen_id]) continue; - const auto my_bus = bus_id_(gen_id); - if(my_bus == _deactivated_bus_id){ - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "Generator::reconnect_connected_buses: Generator with id "; - exc_ << gen_id; - exc_ << " is connected to bus '-1' (meaning disconnected) while you said it was disconnected. Have you called `gridmodel.deactivate_gen(...)` ?."; - throw std::runtime_error(exc_.str()); - } - bus_status[my_bus] = true; // this bus is connected - } -} - void GeneratorContainer::gen_p_per_bus(std::vector & res) const { const int nb_gen = nb(); @@ -526,16 +463,3 @@ void GeneratorContainer::gen_p_per_bus(std::vector & res) const if (p_mw_(gen_id) > 0.) res[my_bus] += p_mw_(gen_id); } } - -void GeneratorContainer::disconnect_if_not_in_main_component(std::vector & busbar_in_main_component){ - const int nb_gen = nb(); - SolverControl unused_solver_control; - for(int gen_id = 0; gen_id < nb_gen; ++gen_id) - { - if(!status_[gen_id]) continue; - const auto my_bus = bus_id_(gen_id); - if(!busbar_in_main_component[my_bus]){ - deactivate(gen_id, unused_solver_control); - } - } -} diff --git a/src/element_container/GeneratorContainer.h b/src/element_container/GeneratorContainer.h index bbb354a..4c087fe 100644 --- a/src/element_container/GeneratorContainer.h +++ b/src/element_container/GeneratorContainer.h @@ -18,7 +18,7 @@ #include "Eigen/SparseLU" #include "Utils.h" -#include "GenericContainer.h" +#include "OneSideContainer.h" /** This class represents the list of all generators. @@ -29,7 +29,7 @@ The convention used for the generator is the same as in pandapower: and for modeling of the Ybus matrix: https://pandapower.readthedocs.io/en/latest/elements/gen.html#electric-model **/ -class GeneratorContainer: public GenericContainer +class GeneratorContainer: public OneSideContainer { public: class GenInfo @@ -111,22 +111,18 @@ class GeneratorContainer: public GenericContainer public: typedef std::tuple< - std::vector, + OneSideContainer::StateRes, bool, std::vector, // voltage_regulator_on - std::vector, // p_mw std::vector, // vm_pu_ - std::vector, // q_mvar_ std::vector, // min_q_ std::vector, // max_q_ - std::vector, // bus_id - std::vector, // status std::vector, // gen_slackbus std::vector // gen_slack_weight_ > StateRes; - GeneratorContainer():turnedoff_gen_pv_(true){}; - GeneratorContainer(bool turnedoff_gen_pv):turnedoff_gen_pv_(turnedoff_gen_pv) {}; + GeneratorContainer():OneSideContainer(), turnedoff_gen_pv_(true){}; + GeneratorContainer(bool turnedoff_gen_pv):OneSideContainer(), turnedoff_gen_pv_(turnedoff_gen_pv) {}; // TODO add pmin and pmax here ! void init(const RealVect & generators_p, @@ -145,8 +141,6 @@ class GeneratorContainer: public GenericContainer const Eigen::VectorXi & generators_bus_id ); - int nb() const { return static_cast(p_mw_.size()); } - // iterator typedef GeneratorConstIterator const_iterator_type; const_iterator_type begin() const {return GeneratorConstIterator(this, 0); } @@ -195,6 +189,7 @@ class GeneratorContainer: public GenericContainer remove_slackbus(gen_id, unused_solver_control); } } + // returns only the gen_id with the highest p that is connected to this bus ! int assign_slack_bus(int slack_bus_id, const std::vector & gen_p_per_bus, @@ -241,7 +236,7 @@ class GeneratorContainer: public GenericContainer void update_slack_weights(Eigen::Ref > could_be_slack, SolverControl & solver_control); - void deactivate(int gen_id, SolverControl & solver_control) { + virtual void deactivate(int gen_id, SolverControl & solver_control) { if (status_[gen_id]){ solver_control.tell_recompute_sbus(); solver_control.tell_pq_changed(); // bus might now be pq @@ -253,41 +248,44 @@ class GeneratorContainer: public GenericContainer } } _deactivate(gen_id, status_); + gen_slackbus_[gen_id] = false; } - void reactivate(int gen_id, SolverControl & solver_control) { + + virtual void reactivate(int gen_id, SolverControl & solver_control) { if(!status_[gen_id]){ solver_control.tell_recompute_sbus(); - solver_control.tell_pq_changed(); // bus might now be pv + // bus might change between pv / pq depending on the state of the generator + // TODO speed optim here + solver_control.tell_pq_changed(); + solver_control.tell_pv_changed(); + if(voltage_regulator_on_[gen_id]) solver_control.tell_v_changed(); - solver_control.tell_pv_changed(); if(gen_slack_weight_[gen_id] != 0. || gen_slackbus_[gen_id]){ solver_control.tell_slack_participate_changed(); solver_control.tell_slack_weight_changed(); } + if(gen_slack_weight_[gen_id] != 0.){ + gen_slackbus_[gen_id] = true; + } } _reactivate(gen_id, status_); } - void change_bus(int gen_id, int new_bus_id, SolverControl & solver_control, int nb_bus) { + virtual void change_bus(int gen_id, int new_bus_id, SolverControl & solver_control, int nb_bus) { if (new_bus_id != bus_id_[gen_id]){ if (gen_slack_weight_[gen_id] != 0. || gen_slackbus_[gen_id]) solver_control.has_slack_participate_changed(); + // bus might change between pv / pq depending on the state of the generator + // TODO speed optim here + solver_control.tell_pq_changed(); + solver_control.tell_pv_changed(); } - _change_bus(gen_id, new_bus_id, bus_id_, solver_control, nb_bus);} - int get_bus(int gen_id) {return _get_bus(gen_id, status_, bus_id_);} - virtual void reconnect_connected_buses(std::vector & bus_status) const; - virtual void disconnect_if_not_in_main_component(std::vector & busbar_in_main_component); - virtual void update_bus_status(std::vector & bus_status) const { - const int nb_gen = nb(); - for(int gen_id = 0; gen_id < nb_gen; ++gen_id) - { - if(!status_[gen_id]) continue; - bus_status[bus_id_[gen_id]] = true; - } - } + _change_bus(gen_id, new_bus_id, bus_id_, solver_control, nb_bus); + } + real_type get_qmin(int gen_id) {return min_q_.coeff(gen_id);} real_type get_qmax(int gen_id) {return max_q_.coeff(gen_id);} - void change_p(int gen_id, real_type new_p, SolverControl & solver_control); void change_v(int gen_id, real_type new_v_pu, SolverControl & solver_control); - void change_q(int gen_id, real_type new_q, SolverControl & solver_control); + void change_v_nothrow(int gen_id, real_type new_v_pu, SolverControl & solver_control); + virtual void change_p_nothrow(int load_id, real_type new_p, SolverControl & solver_control); virtual void fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const; virtual void fillpv(std::vector& bus_pv, @@ -299,14 +297,17 @@ class GeneratorContainer: public GenericContainer RealVect & total_q_min_per_bus, RealVect & total_q_max_per_bus) const; // delta_q_per_gen_ - void compute_results(const Eigen::Ref & Va, - const Eigen::Ref & Vm, - const Eigen::Ref & V, - const std::vector & id_grid_to_solver, - const RealVect & bus_vn_kv, - real_type sn_mva, - bool ac); - void reset_results(); + virtual void compute_results(const Eigen::Ref & Va, + const Eigen::Ref & Vm, + const Eigen::Ref & V, + const std::vector & id_grid_to_solver, + const RealVect & bus_vn_kv, + real_type sn_mva, + bool ac); + void reset_results(){ + OneSideContainer::reset_results(); + } + void set_q(const RealVect & reactive_mismatch, const std::vector & id_grid_to_solver, bool ac, @@ -315,6 +316,7 @@ class GeneratorContainer: public GenericContainer const RealVect & total_q_max_per_bus); void get_vm_for_dc(RealVect & Vm); + /** this functions makes sure that the voltage magnitude of every connected bus is properly used to initialize the ac powerflow @@ -323,13 +325,6 @@ class GeneratorContainer: public GenericContainer virtual void gen_p_per_bus(std::vector & res) const; - tuple3d get_res() const {return tuple3d(res_p_, res_q_, res_v_);} - tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);} - Eigen::Ref get_theta() const {return res_theta_;} - - const std::vector& get_status() const {return status_;} - Eigen::Ref get_bus_id() const {return bus_id_;} - void cout_v(){ for(const auto & el : vm_pu_){ std::cout << "V " << el << std::endl; @@ -337,16 +332,12 @@ class GeneratorContainer: public GenericContainer } protected: // physical properties + RealVect min_q_; + RealVect max_q_; // input data std::vector voltage_regulator_on_; - RealVect p_mw_; RealVect vm_pu_; - RealVect q_mvar_; - RealVect min_q_; - RealVect max_q_; - Eigen::VectorXi bus_id_; - std::vector status_; // remember which generators are "slack bus" std::vector gen_slackbus_; // say for each generator if it's a slack or not @@ -356,12 +347,6 @@ class GeneratorContainer: public GenericContainer // Eigen::VectorXi total_gen_per_bus_; RealVect bus_slack_weight_; // do not sum to 1., for each node of the grid, say the raw contribution for the generator - //output data - RealVect res_p_; // in MW - RealVect res_q_; // in MVar - RealVect res_v_; // in kV - RealVect res_theta_; // in deg (and not rad) - // different parameter of the behaviour of the class bool turnedoff_gen_pv_; // are turned off generators (including one with p=0) pv ? }; diff --git a/src/element_container/LoadContainer.cpp b/src/element_container/LoadContainer.cpp index fedf1f6..d52c779 100644 --- a/src/element_container/LoadContainer.cpp +++ b/src/element_container/LoadContainer.cpp @@ -10,46 +10,16 @@ #include #include -void LoadContainer::init(const RealVect & loads_p, - const RealVect & loads_q, - const Eigen::VectorXi & loads_bus_id) -{ - int size = static_cast(loads_p.size()); - GenericContainer::check_size(loads_p, size, "loads_p"); - GenericContainer::check_size(loads_q, size, "loads_q"); - GenericContainer::check_size(loads_bus_id, size, "loads_bus_id"); - - p_mw_ = loads_p; - q_mvar_ = loads_q; - bus_id_ = loads_bus_id; - status_ = std::vector(loads_p.size(), true); - reset_results(); -} - LoadContainer::StateRes LoadContainer::get_state() const { - std::vector p_mw(p_mw_.begin(), p_mw_.end()); - std::vector q_mvar(q_mvar_.begin(), q_mvar_.end()); - std::vector bus_id(bus_id_.begin(), bus_id_.end()); - std::vector status = status_; - LoadContainer::StateRes res(names_, p_mw, q_mvar, bus_id, status); - return res; + const auto tmp = OneSideContainer::get_state(); + LoadContainer::StateRes res(tmp); + return res; } -void LoadContainer::set_state(LoadContainer::StateRes & my_state ) +void LoadContainer::set_state(LoadContainer::StateRes & my_state) { - names_ = std::get<0>(my_state); - std::vector & p_mw = std::get<1>(my_state); - std::vector & q_mvar = std::get<2>(my_state); - std::vector & bus_id = std::get<3>(my_state); - std::vector & status = std::get<4>(my_state); - // TODO check sizes - - // input data - p_mw_ = RealVect::Map(&p_mw[0], p_mw.size()); - q_mvar_ = RealVect::Map(&q_mvar[0], q_mvar.size()); - bus_id_ = Eigen::VectorXi::Map(&bus_id[0], bus_id.size()); - status_ = status; + OneSideContainer::set_base_state(std::get<0>(my_state)); reset_results(); } @@ -87,80 +57,12 @@ void LoadContainer::compute_results(const Eigen::Ref & Va, real_type sn_mva, bool ac) { - const int nb_load = nb(); - v_kv_from_vpu(Va, Vm, status_, nb_load, bus_id_, id_grid_to_solver, bus_vn_kv, res_v_); - v_deg_from_va(Va, Vm, status_, nb_load, bus_id_, id_grid_to_solver, bus_vn_kv, res_theta_); + OneSideContainer::compute_results_base(Va, Vm, V, id_grid_to_solver, bus_vn_kv, sn_mva, ac); + const int nb_loads = nb(); res_p_ = p_mw_; if(ac) res_q_ = q_mvar_; else{ // no q in DC mode - for(int load_id = 0; load_id < nb_load; ++load_id) res_q_(load_id) = 0.; - } -} - -void LoadContainer::reset_results(){ - // std::cout << "Loads reset_results \n"; - res_p_ = RealVect(nb()); // in MW - res_q_ = RealVect(nb()); // in MVar - res_v_ = RealVect(nb()); // in kV - res_theta_ = RealVect(nb()); // in deg -} - -void LoadContainer::change_p(int load_id, real_type new_p, SolverControl & solver_control) -{ - bool my_status = status_.at(load_id); // and this check that load_id is not out of bound - if(!my_status) - { - std::ostringstream exc_; - exc_ << "LoadContainer::change_p: Impossible to change the active value of a disconnected load (check load id "; - exc_ << load_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); + for(int el_id = 0; el_id < nb_loads; ++el_id) res_q_(el_id) = 0.; } - change_p_nothrow(load_id, new_p, solver_control); -} - -void LoadContainer::change_q(int load_id, real_type new_q, SolverControl & solver_control) -{ - bool my_status = status_.at(load_id); // and this check that load_id is not out of bound - if(!my_status) - { - std::ostringstream exc_; - exc_ << "LoadContainer::change_q: Impossible to change the reactive value of a disconnected load (check load id "; - exc_ << load_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); - } - change_q_nothrow(load_id, new_q, solver_control); -} - -void LoadContainer::reconnect_connected_buses(std::vector & bus_status) const { - const int nb_load = nb(); - for(int load_id = 0; load_id < nb_load; ++load_id) - { - if(!status_[load_id]) continue; - const auto my_bus = bus_id_(load_id); - if(my_bus == _deactivated_bus_id){ - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "LoadContainer::reconnect_connected_buses: Load with id "; - exc_ << load_id; - exc_ << " is connected to bus '-1' (meaning disconnected) while you said it was disconnected. Have you called `gridmodel.deactivate_load(...)` ?."; - throw std::runtime_error(exc_.str()); - } - bus_status[my_bus] = true; // this bus is connected - } -} - -void LoadContainer::disconnect_if_not_in_main_component(std::vector & busbar_in_main_component){ - const int nb_el = nb(); - SolverControl unused_solver_control; - for(int el_id = 0; el_id < nb_el; ++el_id) - { - if(!status_[el_id]) continue; - const auto my_bus = bus_id_(el_id); - if(!busbar_in_main_component[my_bus]){ - deactivate(el_id, unused_solver_control); - } - } } diff --git a/src/element_container/LoadContainer.h b/src/element_container/LoadContainer.h index edfea92..cfdd18c 100644 --- a/src/element_container/LoadContainer.h +++ b/src/element_container/LoadContainer.h @@ -16,7 +16,7 @@ #include "Eigen/SparseLU" #include "Utils.h" -#include "GenericContainer.h" +#include "OneSideContainer.h" /** This class is a container for all loads on the grid. @@ -31,11 +31,8 @@ NOTE: this class is also used for the storage units! So storage units are modele which entails that negative storage: the unit is discharging, power is injected in the grid, positive storage: the unit is charging, power is taken from the grid. **/ -class LoadContainer : public GenericContainer +class LoadContainer : public OneSideContainer { - // TODO make a single class for load and shunt and just specialize the part where the - // TODO powerflow equations are located (when i update the Y matrix) - // iterators part public: class LoadInfo @@ -117,70 +114,32 @@ class LoadContainer : public GenericContainer // regular implementation public: typedef std::tuple< - std::vector, - std::vector, // p_mw - std::vector, // q_mvar - std::vector, // bus_id - std::vector // status + OneSideContainer::StateRes // state of the base class > StateRes; - LoadContainer() {}; + LoadContainer():OneSideContainer(){}; // pickle (python) LoadContainer::StateRes get_state() const; - void set_state(LoadContainer::StateRes & my_state ); - - - void init(const RealVect & loads_p, - const RealVect & loads_q, - const Eigen::VectorXi & loads_bus_id - ); + void set_state(LoadContainer::StateRes & my_state); - int nb() const { return static_cast(p_mw_.size()); } - - void deactivate(int load_id, SolverControl & solver_control) { - if(status_[load_id]){ - solver_control.tell_recompute_sbus(); - } - _deactivate(load_id, status_); - } - void reactivate(int load_id, SolverControl & solver_control) { - if(!status_[load_id]){ - solver_control.tell_recompute_sbus(); - } - _reactivate(load_id, status_); - } - void change_bus(int load_id, int new_bus_id, SolverControl & solver_control, int nb_bus) {_change_bus(load_id, new_bus_id, bus_id_, solver_control, nb_bus);} - int get_bus(int load_id) {return _get_bus(load_id, status_, bus_id_);} - void change_p(int load_id, real_type new_p, SolverControl & solver_control); - void change_p_nothrow(int load_id, real_type new_p, SolverControl & solver_control) + void init(const RealVect & load_p_mw, + const RealVect & load_q_mvar, + const Eigen::VectorXi & load_bus_id + ) { - if (p_mw_(load_id) != new_p) { - solver_control.tell_recompute_sbus(); - p_mw_(load_id) = new_p; - } + OneSideContainer::init_base(load_p_mw, + load_q_mvar, + load_bus_id, + "loads"); + reset_results(); } - void change_q(int load_id, real_type new_q, SolverControl & solver_control); - void change_q_nothrow(int load_id, real_type new_q, SolverControl & solver_control) - { - if (q_mvar_(load_id) != new_q) { - solver_control.tell_recompute_sbus(); - q_mvar_(load_id) = new_q; - } - } - virtual void reconnect_connected_buses(std::vector & bus_status) const; - virtual void disconnect_if_not_in_main_component(std::vector & busbar_in_main_component); virtual void fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const; - virtual void update_bus_status(std::vector & bus_status) const { - const int nb_ = nb(); - for(int el_id = 0; el_id < nb_; ++el_id) - { - if(!status_[el_id]) continue; - bus_status[bus_id_[el_id]] = true; - } - } - + virtual void reset_results() + { + OneSideContainer::reset_results(); + } void compute_results(const Eigen::Ref & Va, const Eigen::Ref & Vm, const Eigen::Ref & V, @@ -188,29 +147,6 @@ class LoadContainer : public GenericContainer const RealVect & bus_vn_kv, real_type sn_mva, bool ac); - void reset_results(); - - tuple3d get_res() const {return tuple3d(res_p_, res_q_, res_v_);} - tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);} - - Eigen::Ref get_theta() const {return res_theta_;} - const std::vector& get_status() const {return status_;} - Eigen::Ref get_bus_id() const {return bus_id_;} - - protected: - // physical properties - - // input data - RealVect p_mw_; - RealVect q_mvar_; - Eigen::VectorXi bus_id_; - std::vector status_; - - //output data - RealVect res_p_; // in MW - RealVect res_q_; // in MVar - RealVect res_v_; // in kV - RealVect res_theta_; // in degree }; #endif //LOAD_CONTAINER_H diff --git a/src/element_container/OneSideContainer.cpp b/src/element_container/OneSideContainer.cpp new file mode 100644 index 0000000..b0afbf1 --- /dev/null +++ b/src/element_container/OneSideContainer.cpp @@ -0,0 +1,114 @@ +// Copyright (c) 2020-2023, RTE (https://www.rte-france.com) +// See AUTHORS.txt +// This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. +// If a copy of the Mozilla Public License, version 2.0 was not distributed with this file, +// you can obtain one at http://mozilla.org/MPL/2.0/. +// SPDX-License-Identifier: MPL-2.0 +// This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform. + +#include "OneSideContainer.h" +#include +#include + +void OneSideContainer::init_base(const RealVect & els_p, + const RealVect & els_q, + const Eigen::VectorXi & els_bus_id, + const std::string & name_el + ) +{ + int size = static_cast(els_p.size()); + check_size(els_p, size, name_el + "_p"); + check_size(els_q, size, name_el + "_q"); + check_size(els_bus_id, size, name_el + "_bus_id"); + + p_mw_ = els_p; + q_mvar_ = els_q; + bus_id_ = els_bus_id; + status_ = std::vector(els_p.size(), true); +} + +OneSideContainer::StateRes OneSideContainer::get_state() const +{ + std::vector p_mw(p_mw_.begin(), p_mw_.end()); + std::vector q_mvar(q_mvar_.begin(), q_mvar_.end()); + std::vector bus_id(bus_id_.begin(), bus_id_.end()); + std::vector status = status_; + OneSideContainer::StateRes res(names_, p_mw, q_mvar, bus_id, status); + return res; +} + +void OneSideContainer::set_base_state(OneSideContainer::StateRes & my_state) +{ + // read data + names_ = std::get<0>(my_state); + std::vector & p_mw = std::get<1>(my_state); + std::vector & q_mvar = std::get<2>(my_state); + std::vector & bus_id = std::get<3>(my_state); + std::vector & status = std::get<4>(my_state); + + // check sizes + const auto size = p_mw.size(); + check_size(names_, size, "names"); + check_size(p_mw, size, "p_mw"); + check_size(q_mvar, size, "q_mvar"); + check_size(bus_id, size, "bus_id"); + check_size(status, size, "status"); + + // input data + p_mw_ = RealVect::Map(&p_mw[0], p_mw.size()); + q_mvar_ = RealVect::Map(&q_mvar[0], q_mvar.size()); + bus_id_ = Eigen::VectorXi::Map(&bus_id[0], bus_id.size()); + status_ = status; +} + +void OneSideContainer::compute_results_base(const Eigen::Ref & Va, + const Eigen::Ref & Vm, + const Eigen::Ref & V, + const std::vector & id_grid_to_solver, + const RealVect & bus_vn_kv, + real_type sn_mva, + bool ac) +{ + const int nb_els = nb(); + v_kv_from_vpu(Va, Vm, status_, nb_els, bus_id_, id_grid_to_solver, bus_vn_kv, res_v_); + v_deg_from_va(Va, Vm, status_, nb_els, bus_id_, id_grid_to_solver, bus_vn_kv, res_theta_); +} + +void OneSideContainer::reset_results(){ + // std::cout << "Loads reset_results \n"; + res_p_ = RealVect(nb()); // in MW + res_q_ = RealVect(nb()); // in MVar + res_v_ = RealVect(nb()); // in kV + res_theta_ = RealVect(nb()); // in deg +} + +void OneSideContainer::reconnect_connected_buses(std::vector & bus_status) const { + const int nb_els = nb(); + for(int el_id = 0; el_id < nb_els; ++el_id) + { + if(!status_[el_id]) continue; + const auto my_bus = bus_id_(el_id); + if(my_bus == _deactivated_bus_id){ + // TODO DEBUG MODE only this in debug mode + std::ostringstream exc_; + exc_ << "OneSideContainer::reconnect_connected_buses: element with id "; + exc_ << el_id; + exc_ << " is connected to bus '-1' (meaning disconnected) while you said it was disconnected. Have you called `gridmodel.deactivate_xxx(...)` ?."; + throw std::runtime_error(exc_.str()); + } + bus_status[my_bus] = true; // this bus is connected + } +} + +void OneSideContainer::disconnect_if_not_in_main_component(std::vector & busbar_in_main_component){ + const int nb_el = nb(); + SolverControl unused_solver_control; + for(int el_id = 0; el_id < nb_el; ++el_id) + { + if(!status_[el_id]) continue; + const auto my_bus = bus_id_(el_id); + if(!busbar_in_main_component[my_bus]){ + deactivate(el_id, unused_solver_control); + } + } +} diff --git a/src/element_container/OneSideContainer.h b/src/element_container/OneSideContainer.h new file mode 100644 index 0000000..56f335d --- /dev/null +++ b/src/element_container/OneSideContainer.h @@ -0,0 +1,152 @@ +// Copyright (c) 2024, RTE (https://www.rte-france.com) +// See AUTHORS.txt +// This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. +// If a copy of the Mozilla Public License, version 2.0 was not distributed with this file, +// you can obtain one at http://mozilla.org/MPL/2.0/. +// SPDX-License-Identifier: MPL-2.0 +// This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform. + +#ifndef ONE_SIDE_CONTAINER_H +#define ONE_SIDE_CONTAINER_H + + +#include "Eigen/Core" +#include "Eigen/Dense" +#include "Eigen/SparseCore" +#include "Eigen/SparseLU" + +#include "Utils.h" +#include "GenericContainer.h" + + +class OneSideContainer : public GenericContainer +{ + // TODO make a single class for load and shunt and just specialize the part where the + // TODO powerflow equations are located (when i update the Y matrix) + + // regular implementation + public: + typedef std::tuple< + std::vector, + std::vector, // p_mw + std::vector, // q_mvar + std::vector, // bus_id + std::vector // status + > StateRes; + + OneSideContainer() {}; + + // pickle (python) + OneSideContainer::StateRes get_state() const; + void set_base_state(OneSideContainer::StateRes & my_state); + + void init_base(const RealVect & els_p, + const RealVect & els_q, + const Eigen::VectorXi & els_bus_id, + const std::string & name_el + ); + + int nb() const { return static_cast(p_mw_.size()); } + int get_bus(int load_id) {return _get_bus(load_id, status_, bus_id_);} + Eigen::Ref get_buses() const {return bus_id_;} + + tuple3d get_res() const {return tuple3d(res_p_, res_q_, res_v_);} + tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);} + + Eigen::Ref get_theta() const {return res_theta_;} + const std::vector& get_status() const {return status_;} + Eigen::Ref get_bus_id() const {return bus_id_;} + + + virtual void deactivate(int el_id, SolverControl & solver_control) { + if(status_[el_id]){ + solver_control.tell_recompute_sbus(); + } + _deactivate(el_id, status_); + } + virtual void reactivate(int el_id, SolverControl & solver_control) { + if(!status_[el_id]){ + solver_control.tell_recompute_sbus(); + } + _reactivate(el_id, status_); + } + virtual void change_bus(int load_id, int new_bus_id, SolverControl & solver_control, int nb_bus) { + _change_bus(load_id, new_bus_id, bus_id_, solver_control, nb_bus); + } + virtual void change_p(int el_id, real_type new_p, SolverControl & solver_control){ + bool my_status = status_.at(el_id); // and this check that el_id is not out of bound + if(!my_status) + { + std::ostringstream exc_; + exc_ << "OneSideContainer::change_p: Impossible to change the active value of a disconnected element (check load id "; + exc_ << el_id; + exc_ << ")"; + throw std::runtime_error(exc_.str()); + } + change_p_nothrow(el_id, new_p, solver_control); + } + virtual void change_p_nothrow(int load_id, real_type new_p, SolverControl & solver_control) + { + if (p_mw_(load_id) != new_p) { + solver_control.tell_recompute_sbus(); + p_mw_(load_id) = new_p; + } + } + virtual void change_q(int el_id, real_type new_q, SolverControl & solver_control) + { + bool my_status = status_.at(el_id); // and this check that el_id is not out of bound + if(!my_status) + { + std::ostringstream exc_; + exc_ << "OneSideContainer::change_q: Impossible to change the reactive value of a disconnected element (check load id "; + exc_ << el_id; + exc_ << ")"; + throw std::runtime_error(exc_.str()); + } + change_q_nothrow(el_id, new_q, solver_control); + } + virtual void change_q_nothrow(int load_id, real_type new_q, SolverControl & solver_control) + { + if (q_mvar_(load_id) != new_q) { + solver_control.tell_recompute_sbus(); + q_mvar_(load_id) = new_q; + } + } + virtual void reconnect_connected_buses(std::vector & bus_status) const; + virtual void disconnect_if_not_in_main_component(std::vector & busbar_in_main_component); + + virtual void update_bus_status(std::vector & bus_status) const { + const int nb_ = nb(); + for(int el_id = 0; el_id < nb_; ++el_id) + { + if(!status_[el_id]) continue; + bus_status[bus_id_[el_id]] = true; + } + } + + void compute_results_base(const Eigen::Ref & Va, + const Eigen::Ref & Vm, + const Eigen::Ref & V, + const std::vector & id_grid_to_solver, + const RealVect & bus_vn_kv, + real_type sn_mva, + bool ac); + virtual void reset_results(); + + protected: + // physical properties + + // input data + RealVect p_mw_; + RealVect q_mvar_; + Eigen::VectorXi bus_id_; + std::vector status_; + + //output data + RealVect res_p_; // in MW + RealVect res_q_; // in MVar + RealVect res_v_; // in kV + RealVect res_theta_; // in degree +}; + +#endif //ONE_SIDE_CONTAINER_H \ No newline at end of file diff --git a/src/element_container/SGenContainer.cpp b/src/element_container/SGenContainer.cpp index 8690b74..462ef5b 100644 --- a/src/element_container/SGenContainer.cpp +++ b/src/element_container/SGenContainer.cpp @@ -9,6 +9,7 @@ #include "SGenContainer.h" #include + void SGenContainer::init(const RealVect & sgen_p, const RealVect & sgen_q, const RealVect & sgen_pmin, @@ -18,69 +19,49 @@ void SGenContainer::init(const RealVect & sgen_p, const Eigen::VectorXi & sgen_bus_id) { int size = static_cast(sgen_p.size()); - GenericContainer::check_size(sgen_p, size, "sgen_p"); - GenericContainer::check_size(sgen_q, size, "sgen_q"); + OneSideContainer::init_base(sgen_p, sgen_q, sgen_bus_id, "static_generators"); + GenericContainer::check_size(sgen_pmin, size, "sgen_pmin"); GenericContainer::check_size(sgen_pmax, size, "sgen_pmax"); GenericContainer::check_size(sgen_qmin, size, "sgen_qmin"); GenericContainer::check_size(sgen_qmax, size, "sgen_qmax"); - GenericContainer::check_size(sgen_bus_id, size, "sgen_bus_id"); - p_mw_ = sgen_p; - q_mvar_ = sgen_q; p_min_mw_ = sgen_pmin; p_max_mw_ = sgen_pmax; q_min_mvar_ = sgen_qmin; q_max_mvar_ = sgen_qmax; - bus_id_ = sgen_bus_id; - status_ = std::vector(sgen_p.size(), true); reset_results(); } SGenContainer::StateRes SGenContainer::get_state() const { - std::vector p_mw(p_mw_.begin(), p_mw_.end()); - std::vector q_mvar(q_mvar_.begin(), q_mvar_.end()); std::vector p_min(p_min_mw_.begin(), p_min_mw_.end()); std::vector p_max(p_max_mw_.begin(), p_max_mw_.end()); std::vector q_min(q_min_mvar_.begin(), q_min_mvar_.end()); std::vector q_max(q_max_mvar_.begin(), q_max_mvar_.end()); - std::vector bus_id(bus_id_.begin(), bus_id_.end()); - std::vector status = status_; - SGenContainer::StateRes res(names_, p_mw, q_mvar, p_min, p_max, q_min, q_max, bus_id, status); + SGenContainer::StateRes res(OneSideContainer::get_state(), p_min, p_max, q_min, q_max); return res; } void SGenContainer::set_state(SGenContainer::StateRes & my_state ) { - names_ = std::get<0>(my_state); - std::vector & p_mw = std::get<1>(my_state); - std::vector & q_mvar = std::get<2>(my_state); - std::vector & p_min = std::get<3>(my_state); - std::vector & p_max = std::get<4>(my_state); - std::vector & q_min = std::get<5>(my_state); - std::vector & q_max = std::get<6>(my_state); - std::vector & bus_id = std::get<7>(my_state); - std::vector & status = std::get<8>(my_state); - auto size = p_mw.size(); - GenericContainer::check_size(p_mw, size, "p_mw"); - GenericContainer::check_size(q_mvar, size, "q_mvar"); + OneSideContainer::set_base_state(std::get<0>(my_state)); + + std::vector & p_min = std::get<1>(my_state); + std::vector & p_max = std::get<2>(my_state); + std::vector & q_min = std::get<3>(my_state); + std::vector & q_max = std::get<4>(my_state); + const auto size = nb(); + GenericContainer::check_size(p_min, size, "p_min"); GenericContainer::check_size(p_max, size, "p_max"); GenericContainer::check_size(q_min, size, "q_min"); GenericContainer::check_size(q_max, size, "q_max"); - GenericContainer::check_size(bus_id, size, "bus_id"); - GenericContainer::check_size(status, size, "status"); - p_mw_ = RealVect::Map(&p_mw[0], size); - q_mvar_ = RealVect::Map(&q_mvar[0], size); - q_mvar_ = RealVect::Map(&q_mvar[0], size); p_min_mw_ = RealVect::Map(&p_min[0], size); p_max_mw_ = RealVect::Map(&p_max[0], size); q_min_mvar_ = RealVect::Map(&q_min[0], size); q_max_mvar_ = RealVect::Map(&q_max[0], size); - bus_id_ = Eigen::VectorXi::Map(&bus_id[0], bus_id.size()); - status_ = status; reset_results(); } @@ -114,9 +95,8 @@ void SGenContainer::compute_results(const Eigen::Ref & Va, real_type sn_mva, bool ac) { + OneSideContainer::compute_results_base(Va, Vm, V, id_grid_to_solver, bus_vn_kv, sn_mva, ac); const int nb_sgen = nb(); - v_kv_from_vpu(Va, Vm, status_, nb_sgen, bus_id_, id_grid_to_solver, bus_vn_kv, res_v_); - v_deg_from_va(Va, Vm, status_, nb_sgen, bus_id_, id_grid_to_solver, bus_vn_kv, res_theta_); res_p_ = p_mw_; if(ac) res_q_ = q_mvar_; else{ @@ -124,86 +104,3 @@ void SGenContainer::compute_results(const Eigen::Ref & Va, for(int sgen_id = 0; sgen_id < nb_sgen; ++sgen_id) res_q_(sgen_id) = 0.; } } - -void SGenContainer::reset_results(){ - res_p_ = RealVect(nb()); // in MW - res_q_ = RealVect(nb()); // in MVar - res_v_ = RealVect(nb()); // in kV - res_theta_ = RealVect(nb()); // in deg -} - -void SGenContainer::change_p(int sgen_id, real_type new_p, SolverControl & solver_control) -{ - bool my_status = status_.at(sgen_id); // and this check that load_id is not out of bound - if(!my_status) - { - std::ostringstream exc_; - exc_ << "SGenContainer::change_p: Impossible to change the active value of a disconnected static generator (check sgen id "; - exc_ << sgen_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); - } - if (p_mw_(sgen_id) != new_p){ - solver_control.tell_recompute_sbus(); - p_mw_(sgen_id) = new_p; - } -} - -void SGenContainer::change_q(int sgen_id, real_type new_q, SolverControl & solver_control) -{ - bool my_status = status_.at(sgen_id); // and this check that load_id is not out of bound - if(!my_status) - { - std::ostringstream exc_; - exc_ << "SGenContainer::change_q: Impossible to change the reactive value of a disconnected static generator (check sgen id "; - exc_ << sgen_id; - exc_ << ")"; - throw std::runtime_error(exc_.str()); - } - if (q_mvar_(sgen_id) != new_q){ - solver_control.tell_recompute_sbus(); - q_mvar_(sgen_id) = new_q; - } -} - -void SGenContainer::reconnect_connected_buses(std::vector & bus_status) const { - const int nb_sgen = nb(); - for(int sgen_id = 0; sgen_id < nb_sgen; ++sgen_id) - { - if(!status_[sgen_id]) continue; - const auto my_bus = bus_id_(sgen_id); - if(my_bus == _deactivated_bus_id){ - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "SGenContainer::reconnect_connected_buses: Static Generator with id "; - exc_ << sgen_id; - exc_ << " is connected to bus '-1' (meaning disconnected) while you said it was disconnected. Have you called `gridmodel.deactivate_sgen(...)` ?."; - throw std::runtime_error(exc_.str()); - } - bus_status[my_bus] = true; // this bus is connected - } -} - -void SGenContainer::gen_p_per_bus(std::vector & res) const -{ - const int nb_gen = nb(); - for(int sgen_id = 0; sgen_id < nb_gen; ++sgen_id) - { - if(!status_[sgen_id]) continue; - const auto my_bus = bus_id_(sgen_id); - res[my_bus] += p_mw_(sgen_id); - } -} - -void SGenContainer::disconnect_if_not_in_main_component(std::vector & busbar_in_main_component){ - const int nb_el = nb(); - SolverControl unused_solver_control; - for(int el_id = 0; el_id < nb_el; ++el_id) - { - if(!status_[el_id]) continue; - const auto my_bus = bus_id_(el_id); - if(!busbar_in_main_component[my_bus]){ - deactivate(el_id, unused_solver_control); - } - } -} diff --git a/src/element_container/SGenContainer.h b/src/element_container/SGenContainer.h index 0540147..e185400 100644 --- a/src/element_container/SGenContainer.h +++ b/src/element_container/SGenContainer.h @@ -16,7 +16,7 @@ #include "Eigen/SparseLU" #include "Utils.h" -#include "GenericContainer.h" +#include "OneSideContainer.h" /** This class is a container for all static generator (PQ generators) on the grid. @@ -28,7 +28,7 @@ The convention used for the static is the same as in pandapower: and for modeling of the Ybus matrix: https://pandapower.readthedocs.io/en/latest/elements/sgen.html#electric-model **/ -class SGenContainer: public GenericContainer +class SGenContainer: public OneSideContainer { // TODO make a single class for load and shunt and just specialize the part where the // TODO powerflow equations are located (when i update the Y matrix) @@ -129,18 +129,14 @@ class SGenContainer: public GenericContainer public: typedef std::tuple< - std::vector, - std::vector, // p_mw - std::vector, // q_mvar + OneSideContainer::StateRes, std::vector, // p_min std::vector, // p_max std::vector, // q_min - std::vector, // q_max - std::vector, // bus_id - std::vector // status + std::vector // q_max > StateRes; - SGenContainer() {}; + SGenContainer():OneSideContainer() {}; // pickle (python) SGenContainer::StateRes get_state() const; @@ -155,38 +151,8 @@ class SGenContainer: public GenericContainer const RealVect & sgen_qmax, const Eigen::VectorXi & sgen_bus_id ); - - int nb() const { return static_cast(p_mw_.size()); } - - void deactivate(int sgen_id, SolverControl & solver_control) { - if(status_[sgen_id]){ - solver_control.tell_recompute_sbus(); - } - _deactivate(sgen_id, status_); - } - void reactivate(int sgen_id, SolverControl & solver_control) { - if(!status_[sgen_id]){ - solver_control.tell_recompute_sbus(); - } - _reactivate(sgen_id, status_); - } - void change_bus(int sgen_id, int new_bus_id, SolverControl & solver_control, int nb_bus) {_change_bus(sgen_id, new_bus_id, bus_id_, solver_control, nb_bus);} - int get_bus(int sgen_id) {return _get_bus(sgen_id, status_, bus_id_);} - void change_p(int sgen_id, real_type new_p, SolverControl & solver_control); - void change_q(int sgen_id, real_type new_q, SolverControl & solver_control); - virtual void reconnect_connected_buses(std::vector & bus_status) const; - virtual void disconnect_if_not_in_main_component(std::vector & busbar_in_main_component); virtual void fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const ; - virtual void gen_p_per_bus(std::vector & res) const; - virtual void update_bus_status(std::vector & bus_status) const { - const int nb_ = nb(); - for(int el_id = 0; el_id < nb_; ++el_id) - { - if(!status_[el_id]) continue; - bus_status[bus_id_[el_id]] = true; - } - } void compute_results(const Eigen::Ref & Va, const Eigen::Ref & Vm, @@ -195,13 +161,21 @@ class SGenContainer: public GenericContainer const RealVect & bus_vn_kv, real_type sn_mva, bool ac); - void reset_results(); + virtual void reset_results() + { + OneSideContainer::reset_results(); + } - tuple3d get_res() const {return tuple3d(res_p_, res_q_, res_v_);} - tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);} - Eigen::Ref get_theta() const {return res_theta_;} - const std::vector& get_status() const {return status_;} - Eigen::Ref get_bus_id() const {return bus_id_;} + void gen_p_per_bus(std::vector & res) const + { + const int nb_gen = nb(); + for(int sgen_id = 0; sgen_id < nb_gen; ++sgen_id) + { + if(!status_[sgen_id]) continue; + const auto my_bus = bus_id_(sgen_id); + res[my_bus] += p_mw_(sgen_id); + } + } protected: // physical properties @@ -211,16 +185,8 @@ class SGenContainer: public GenericContainer RealVect q_max_mvar_; // input data - RealVect p_mw_; - RealVect q_mvar_; - Eigen::VectorXi bus_id_; - std::vector status_; //output data - RealVect res_p_; // in MW - RealVect res_q_; // in MVar - RealVect res_v_; // in kV - RealVect res_theta_; // in degree }; #endif //SGEN_CONTAINER_H diff --git a/src/element_container/ShuntContainer.cpp b/src/element_container/ShuntContainer.cpp index 4bd38a5..9ebec54 100644 --- a/src/element_container/ShuntContainer.cpp +++ b/src/element_container/ShuntContainer.cpp @@ -10,46 +10,15 @@ #include -void ShuntContainer::init(const RealVect & shunt_p_mw, - const RealVect & shunt_q_mvar, - const Eigen::VectorXi & shunt_bus_id) -{ - int size = static_cast(shunt_p_mw.size()); - GenericContainer::check_size(shunt_p_mw, size, "shunt_p_mw"); - GenericContainer::check_size(shunt_q_mvar, size, "shunt_q_mvar"); - GenericContainer::check_size(shunt_bus_id, size, "shunt_bus_id"); - - p_mw_ = shunt_p_mw; - q_mvar_ = shunt_q_mvar; - bus_id_ = shunt_bus_id; - status_ = std::vector(p_mw_.size(), true); // by default everything is connected - reset_results(); -} - ShuntContainer::StateRes ShuntContainer::get_state() const { - std::vector p_mw(p_mw_.begin(), p_mw_.end()); - std::vector q_mvar(q_mvar_.begin(), q_mvar_.end()); - std::vector bus_id(bus_id_.begin(), bus_id_.end()); - std::vector status = status_; - ShuntContainer::StateRes res(names_, p_mw, q_mvar, bus_id, status); + ShuntContainer::StateRes res(OneSideContainer::get_state()); return res; } void ShuntContainer::set_state(ShuntContainer::StateRes & my_state ) { - names_ = std::get<0>(my_state); - std::vector & p_mw = std::get<1>(my_state); - std::vector & q_mvar = std::get<2>(my_state); - std::vector & bus_id = std::get<3>(my_state); - std::vector & status = std::get<4>(my_state); - // TODO check sizes - - // input data - p_mw_ = RealVect::Map(&p_mw[0], p_mw.size()); - q_mvar_ = RealVect::Map(&q_mvar[0], q_mvar.size()); - bus_id_ = Eigen::VectorXi::Map(&bus_id[0], bus_id.size()); - status_ = status; + OneSideContainer::set_base_state(std::get<0>(my_state)); reset_results(); } @@ -133,10 +102,6 @@ void ShuntContainer::fillSbus(CplxVect & Sbus, const std::vector & id_grid_ } } -void ShuntContainer::fillYbus_spmat(Eigen::SparseMatrix & res, bool ac, const std::vector & id_grid_to_solver){ - throw std::runtime_error("ShuntContainer::fillYbus_spmat: should not be used anymore !"); -} - void ShuntContainer::compute_results(const Eigen::Ref & Va, const Eigen::Ref & Vm, const Eigen::Ref & V, @@ -145,11 +110,8 @@ void ShuntContainer::compute_results(const Eigen::Ref & Va, real_type sn_mva, bool ac) { + OneSideContainer::compute_results_base(Va, Vm, V, id_grid_to_solver, bus_vn_kv, sn_mva, ac); const int nb_shunt = static_cast(p_mw_.size()); - v_kv_from_vpu(Va, Vm, status_, nb_shunt, bus_id_, id_grid_to_solver, bus_vn_kv, res_v_); - v_deg_from_va(Va, Vm, status_, nb_shunt, bus_id_, id_grid_to_solver, bus_vn_kv, res_theta_); - // res_p_ = RealVect::Constant(nb_shunt, my_zero_); - // res_q_ = RealVect::Constant(nb_shunt, my_zero_); for(int shunt_id = 0; shunt_id < nb_shunt; ++shunt_id){ if(!status_[shunt_id]) { res_p_(shunt_id) = my_zero_; @@ -171,62 +133,3 @@ void ShuntContainer::compute_results(const Eigen::Ref & Va, else res_q_(shunt_id) = my_zero_; } } - -void ShuntContainer::reset_results(){ - res_p_ = RealVect(nb()); // in MW - res_q_ = RealVect(nb()); // in MVar - res_v_ = RealVect(nb()); // in kV - res_theta_ = RealVect(nb()); // in deg -} - -void ShuntContainer::change_p(int shunt_id, real_type new_p, SolverControl & solver_control) -{ - bool my_status = status_.at(shunt_id); // and this check that load_id is not out of bound - if(!my_status) throw std::runtime_error("Impossible to change the active value of a disconnected shunt"); - if(p_mw_(shunt_id) != new_p){ - solver_control.tell_recompute_ybus(); - solver_control.tell_recompute_sbus(); // in dc mode sbus is modified - p_mw_(shunt_id) = new_p; - } -} - -void ShuntContainer::change_q(int shunt_id, real_type new_q, SolverControl & solver_control) -{ - bool my_status = status_.at(shunt_id); // and this check that load_id is not out of bound - if(!my_status) throw std::runtime_error("Impossible to change the reactive value of a disconnected shunt"); - if(q_mvar_(shunt_id) != new_q){ - solver_control.tell_recompute_ybus(); - q_mvar_(shunt_id) = new_q; - } -} - -void ShuntContainer::reconnect_connected_buses(std::vector & bus_status) const { - const int nb_shunt = nb(); - for(int shunt_id = 0; shunt_id < nb_shunt; ++shunt_id) - { - if(!status_[shunt_id]) continue; - const auto my_bus = bus_id_(shunt_id); - if(my_bus == _deactivated_bus_id){ - // TODO DEBUG MODE only this in debug mode - std::ostringstream exc_; - exc_ << "ShuntContainer::reconnect_connected_buses: Shunt with id "; - exc_ << shunt_id; - exc_ << " is connected to bus '-1' (meaning disconnected) while you said it was disconnected. Have you called `gridmodel.deactivate_shunt(...)` ?."; - throw std::runtime_error(exc_.str()); - } - bus_status[my_bus] = true; // this bus is connected - } -} - -void ShuntContainer::disconnect_if_not_in_main_component(std::vector & busbar_in_main_component){ - const int nb_el = nb(); - SolverControl unused_solver_control; - for(int el_id = 0; el_id < nb_el; ++el_id) - { - if(!status_[el_id]) continue; - const auto my_bus = bus_id_(el_id); - if(!busbar_in_main_component[my_bus]){ - deactivate(el_id, unused_solver_control); - } - } -} diff --git a/src/element_container/ShuntContainer.h b/src/element_container/ShuntContainer.h index e0fd79c..d91e06a 100644 --- a/src/element_container/ShuntContainer.h +++ b/src/element_container/ShuntContainer.h @@ -15,7 +15,7 @@ #include "Eigen/SparseLU" #include "Utils.h" -#include "GenericContainer.h" +#include "OneSideContainer.h" /** This class is a container for all shunts on the grid. @@ -26,7 +26,7 @@ The convention used for the shunt is the same as in pandapower: and for modeling of the Ybus matrix: https://pandapower.readthedocs.io/en/latest/elements/shunt.html#electric-model **/ -class ShuntContainer : public GenericContainer +class ShuntContainer : public OneSideContainer { // iterators part public: @@ -107,50 +107,26 @@ class ShuntContainer : public GenericContainer } public: - typedef std::tuple< - std::vector, - std::vector, // p_mw - std::vector, // q_mvar - std::vector, // bus_id - std::vector // status - > StateRes; + typedef std::tuple StateRes; - ShuntContainer() {}; + ShuntContainer():OneSideContainer() {}; - void init(const RealVect & shunt_p_mw, - const RealVect & shunt_q_mvar, - const Eigen::VectorXi & shunt_bus_id - ); + + void init(const RealVect & load_p_mw, + const RealVect & load_q_mvar, + const Eigen::VectorXi & load_bus_id + ) + { + OneSideContainer::init_base(load_p_mw, + load_q_mvar, + load_bus_id, + "shunts"); + reset_results(); + } // pickle (python) ShuntContainer::StateRes get_state() const; void set_state(ShuntContainer::StateRes & my_state ); - - - int nb() const { return static_cast(p_mw_.size()); } - - void deactivate(int shunt_id, SolverControl & solver_control) { - if(status_[shunt_id]){ - solver_control.tell_recompute_sbus(); // DC - solver_control.tell_recompute_ybus(); // AC - } - _deactivate(shunt_id, status_); - } - void reactivate(int shunt_id, SolverControl & solver_control) { - if(!status_[shunt_id]){ - solver_control.tell_recompute_sbus(); // DC - solver_control.tell_recompute_ybus(); // AC - } - _reactivate(shunt_id, status_); - } - void change_bus(int shunt_id, int new_bus_id, SolverControl & solver_control, int nb_bus) {_change_bus(shunt_id, new_bus_id, bus_id_, solver_control, nb_bus);} - void change_p(int shunt_id, real_type new_p, SolverControl & solver_control); - void change_q(int shunt_id, real_type new_q, SolverControl & solver_control); - int get_bus(int shunt_id) const {return _get_bus(shunt_id, status_, bus_id_);} - Eigen::Ref get_buses() const {return bus_id_;} - - virtual void reconnect_connected_buses(std::vector & bus_status) const; - virtual void disconnect_if_not_in_main_component(std::vector & busbar_in_main_component); virtual void fillYbus(std::vector > & res, bool ac, @@ -161,16 +137,7 @@ class ShuntContainer : public GenericContainer const std::vector & id_grid_to_solver, real_type sn_mva, FDPFMethod xb_or_bx) const; - virtual void fillYbus_spmat(Eigen::SparseMatrix & res, bool ac, const std::vector & id_grid_to_solver); virtual void fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const; // in DC i need that - virtual void update_bus_status(std::vector & bus_status) const { - const int nb_ = nb(); - for(int el_id = 0; el_id < nb_; ++el_id) - { - if(!status_[el_id]) continue; - bus_status[bus_id_[el_id]] = true; - } - } void compute_results(const Eigen::Ref & Va, const Eigen::Ref & Vm, @@ -179,7 +146,11 @@ class ShuntContainer : public GenericContainer const RealVect & bus_vn_kv, real_type sn_mva, bool ac); - void reset_results(); + + virtual void reset_results() + { + OneSideContainer::reset_results(); + } tuple3d get_res() const {return tuple3d(res_p_, res_q_, res_v_);} tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);} @@ -192,16 +163,9 @@ class ShuntContainer : public GenericContainer // physical properties // input data - RealVect p_mw_; - RealVect q_mvar_; - Eigen::VectorXi bus_id_; - std::vector status_; //output data - RealVect res_p_; // in MW - RealVect res_q_; // in MVar - RealVect res_v_; // in kV - RealVect res_theta_; // in kV + }; #endif //SHUNT_CONTAINER_H From db186eb7ab2ac28df9010a51113da77fd23813ca Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Wed, 18 Dec 2024 16:52:05 +0100 Subject: [PATCH 2/3] trying to debug slack disconnection bug [skip ci] Signed-off-by: DONNOT Benjamin --- src/GridModel.cpp | 14 +++++++++----- src/GridModel.h | 5 +++-- src/element_container/GeneratorContainer.cpp | 5 +++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/GridModel.cpp b/src/GridModel.cpp index b4c826e..0b94dfe 100644 --- a/src/GridModel.cpp +++ b/src/GridModel.cpp @@ -540,7 +540,9 @@ CplxVect GridModel::pre_process_solver(const CplxVect & Vinit, if (solver_control.need_reset_solver() || solver_control.ybus_change_sparsity_pattern() || solver_control.has_dimension_changed()){ - init_Ybus(Ybus, id_me_to_solver, id_solver_to_me); + init_converter_bus_id(id_me_to_solver, id_solver_to_me); + const int nb_bus_solver = static_cast(id_solver_to_me.size()); + init_Ybus(Ybus, nb_bus_solver); } if (solver_control.need_reset_solver() || solver_control.ybus_change_sparsity_pattern() || @@ -642,9 +644,9 @@ void GridModel::process_results(bool conv, } } -void GridModel::init_Ybus(Eigen::SparseMatrix & Ybus, - std::vector& id_me_to_solver, - std::vector& id_solver_to_me){ +void GridModel::init_converter_bus_id(std::vector& id_me_to_solver, + std::vector& id_solver_to_me){ + //TODO get disconnected bus !!! (and have some conversion for it) //1. init the conversion bus const int nb_bus_init = static_cast(bus_vn_kv_.size()); @@ -660,8 +662,10 @@ void GridModel::init_Ybus(Eigen::SparseMatrix & Ybus, ++bus_id_solver; } } - const int nb_bus_solver = static_cast(id_solver_to_me.size()); +} +void GridModel::init_Ybus(Eigen::SparseMatrix & Ybus, + int nb_bus_solver){ Ybus = Eigen::SparseMatrix(nb_bus_solver, nb_bus_solver); Ybus.reserve(nb_bus_solver + 2*powerlines_.nb() + 2*trafos_.nb()); } diff --git a/src/GridModel.h b/src/GridModel.h index 16a1858..0ba012d 100644 --- a/src/GridModel.h +++ b/src/GridModel.h @@ -1049,8 +1049,9 @@ class GridModel : public GenericContainer // init the Ybus matrix (its size, it is filled up elsewhere) and also the // converter from "my bus id" to the "solver bus id" (id_me_to_solver and id_solver_to_me) void init_Ybus(Eigen::SparseMatrix & Ybus, - std::vector & id_me_to_solver, - std::vector& id_solver_to_me); + int nb_bus_solver); + void init_converter_bus_id(std::vector& id_me_to_solver, + std::vector& id_solver_to_me); // converts the slack_bus_id from gridmodel ordering into solver ordering void init_slack_bus(const CplxVect & Sbus, diff --git a/src/element_container/GeneratorContainer.cpp b/src/element_container/GeneratorContainer.cpp index f8c3b6d..266d62c 100644 --- a/src/element_container/GeneratorContainer.cpp +++ b/src/element_container/GeneratorContainer.cpp @@ -292,6 +292,11 @@ void GeneratorContainer::set_vm(CplxVect & V, const std::vector & id_grid_t if ((!turnedoff_gen_pv_) && pseudo_off) continue; // in this case turned off generators are not pv bus_id_me = bus_id_(gen_id); + std::cout << "gen_id " << gen_id << std::endl; + std::cout << "id_grid_to_solver.size() " << id_grid_to_solver.size() << std::endl; + std::cout << "bus_id_me " << bus_id_me << std::endl; + std::cout << "======== " << std::endl; + bus_id_solver = id_grid_to_solver[bus_id_me]; if(bus_id_solver == _deactivated_bus_id){ // TODO DEBUG MODE only this in debug mode From cf804675a64949fe161d3e0ed10c3751cf03a7c7 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Sun, 22 Dec 2024 15:53:30 +0100 Subject: [PATCH 3/3] in the middle of fixing the bug with the disconnected gen [skip ci] Signed-off-by: DONNOT Benjamin --- CHANGELOG.rst | 3 ++- docs/conf.py | 2 +- lightsim2grid/__init__.py | 2 +- setup.py | 2 +- src/element_container/GeneratorContainer.cpp | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a38efaa..651d013 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,12 +29,13 @@ TODO: in `main.cpp` check the returned policy of pybind11 and also the `py::call TODO: a cpp class that is able to compute (DC powerflow) ContingencyAnalysis and TimeSeries using PTDF and LODF TODO: integration test with pandapower (see `pandapower/contingency/contingency.py` and import `lightsim2grid_installed` and check it's True) -[0.10.0.post1] 2024-12-xx +[0.10.1.dev0] 2025-xx-yy ---------------------------- - [FIXED] an error when changing of bus one of the slack (did not trigger the recompute of pv bus ids) - [FIXED] an issue when turning off a generator: it was still declared as "slack" if it was one. +- [FIXED] could not disconnect a generator when it was a slack bus - [IMPROVED] refactoring of the c++ side container element to reduce code (for "one end" elements such as loads, generators, static generators and shunts) diff --git a/docs/conf.py b/docs/conf.py index e3d3412..55bef47 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Benjamin DONNOT' # The full version, including alpha/beta/rc tags -release = "0.10.0.post1" +release = "0.10.1.dev0" version = '0.10' # -- General configuration --------------------------------------------------- diff --git a/lightsim2grid/__init__.py b/lightsim2grid/__init__.py index 7304d62..b5faca0 100644 --- a/lightsim2grid/__init__.py +++ b/lightsim2grid/__init__.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform. -__version__ = "0.10.0.post1" +__version__ = "0.10.1.dev0" __all__ = ["newtonpf", "SolverType", "ErrorType", "solver", "compilation_options"] diff --git a/setup.py b/setup.py index 17431b9..76c0edf 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from pybind11.setup_helpers import Pybind11Extension, build_ext -__version__ = "0.10.0.post1" +__version__ = "0.10.1.dev0" KLU_SOLVER_AVAILABLE = False # Try to link against SuiteSparse (if available) diff --git a/src/element_container/GeneratorContainer.cpp b/src/element_container/GeneratorContainer.cpp index 266d62c..17d66b3 100644 --- a/src/element_container/GeneratorContainer.cpp +++ b/src/element_container/GeneratorContainer.cpp @@ -292,10 +292,10 @@ void GeneratorContainer::set_vm(CplxVect & V, const std::vector & id_grid_t if ((!turnedoff_gen_pv_) && pseudo_off) continue; // in this case turned off generators are not pv bus_id_me = bus_id_(gen_id); - std::cout << "gen_id " << gen_id << std::endl; - std::cout << "id_grid_to_solver.size() " << id_grid_to_solver.size() << std::endl; - std::cout << "bus_id_me " << bus_id_me << std::endl; - std::cout << "======== " << std::endl; + // std::cout << "gen_id " << gen_id << std::endl; + // std::cout << "id_grid_to_solver.size() " << id_grid_to_solver.size() << std::endl; + // std::cout << "bus_id_me " << bus_id_me << std::endl; + // std::cout << "======== " << std::endl; bus_id_solver = id_grid_to_solver[bus_id_me]; if(bus_id_solver == _deactivated_bus_id){