From 800573b78e6a46b80b5c0851e6303144e2ee0941 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 9 Nov 2023 17:49:59 +0100 Subject: [PATCH] adding possibility have non pv generators --- CHANGELOG.rst | 1 + lightsim2grid/gridmodel/from_pypowsybl.py | 14 ++-- src/DataGen.cpp | 78 ++++++++++++++++++----- src/DataGen.h | 20 ++++++ src/GridModel.h | 10 +++ src/main.cpp | 3 + 6 files changed, 105 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f3cda35..4629d1d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,7 @@ Change Log - [ADDED] sets of methods to extract the main component of a grid and perform powerflow only on this one. - [ADDED] possibility to set / retrieve the names of each elements of the grid. +- [ADDED] embed in the generator models the "non pv" behaviour. (TODO need to be able to change Q from python side) - [IMPROVED] now performing the new grid2op `create_test_suite` - [IMPROVED] now lightsim2grid properly throw `BackendError` diff --git a/lightsim2grid/gridmodel/from_pypowsybl.py b/lightsim2grid/gridmodel/from_pypowsybl.py index 39d2a2d..375fa9d 100644 --- a/lightsim2grid/gridmodel/from_pypowsybl.py +++ b/lightsim2grid/gridmodel/from_pypowsybl.py @@ -78,12 +78,14 @@ def init(net : pypo.network, min_q[~np.isfinite(min_q)] = np.finfo(np.float32).min * 0.5 + 1. max_q[~np.isfinite(max_q)] = np.finfo(np.float32).max * 0.5 - 1. gen_bus, gen_disco = _aux_get_bus(bus_df, df_gen) - model.init_generators(df_gen["target_p"].values, - df_gen["target_v"].values / voltage_levels.loc[df_gen["voltage_level_id"].values]["nominal_v"].values, - min_q, - max_q, - gen_bus - ) + model.init_generators_full(df_gen["target_p"].values, + df_gen["target_v"].values / voltage_levels.loc[df_gen["voltage_level_id"].values]["nominal_v"].values, + df_gen["target_q"].values, + df_gen["voltage_regulator_on"].values, + min_q, + max_q, + gen_bus + ) for gen_id, is_disco in enumerate(gen_disco): if is_disco: model.deactivate_gen(gen_id) diff --git a/src/DataGen.cpp b/src/DataGen.cpp index b110ff5..db87472 100644 --- a/src/DataGen.cpp +++ b/src/DataGen.cpp @@ -45,6 +45,22 @@ void DataGen::init(const RealVect & generators_p, 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()); +} + +void DataGen::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); + voltage_regulator_on_ = voltage_regulator_on; + q_mvar_ = generators_q; } @@ -52,13 +68,17 @@ DataGen::StateRes DataGen::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_; - DataGen::StateRes res(names_, turnedoff_gen_pv_, p_mw, vm_pu, min_q, max_q, bus_id, status, slack_bus, slack_weight); + DataGen::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); return res; } @@ -69,19 +89,23 @@ void DataGen::set_state(DataGen::StateRes & my_state) turnedoff_gen_pv_ = std::get<1>(my_state); // the generators themelves - std::vector & p_mw = std::get<2>(my_state); - 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 & bus_id = std::get<6>(my_state); - std::vector & status = std::get<7>(my_state); - std::vector & slack_bus = std::get<8>(my_state); - std::vector & slack_weight = std::get<9>(my_state); + 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 + 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()); @@ -118,7 +142,7 @@ RealVect DataGen::get_slack_weights(Eigen::Index nb_bus_solver, const std::vecto void DataGen::fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const { const int nb_gen = nb(); int bus_id_me, bus_id_solver; - real_type tmp; + cplx_type tmp; for(int gen_id = 0; gen_id < nb_gen; ++gen_id){ // i don't do anything if the load is disconnected if(!status_[gen_id]) continue; @@ -133,7 +157,11 @@ void DataGen::fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solv exc_ << " is connected to a disconnected bus while being connected to the grid."; throw std::runtime_error(exc_.str()); } - tmp = p_mw_(gen_id); + tmp = {p_mw_(gen_id), 0.}; + if(!voltage_regulator_on_[gen_id]){ + // gen is pq if voltage regulaton is off + tmp += my_i * q_mvar_(gen_id); + } Sbus.coeffRef(bus_id_solver) += tmp; } } @@ -148,12 +176,11 @@ void DataGen::fillpv(std::vector & bus_pv, for(int gen_id = 0; gen_id < nb_gen; ++gen_id){ // i don't do anything if the generator is disconnected if(!status_[gen_id]) continue; + if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv + if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv bus_id_me = bus_id_(gen_id); bus_id_solver = id_grid_to_solver[bus_id_me]; - - if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv - if(bus_id_solver == _deactivated_bus_id){ // TODO DEBUG MODE only this in debug mode std::ostringstream exc_; @@ -162,7 +189,7 @@ void DataGen::fillpv(std::vector & bus_pv, exc_ << " is connected to a disconnected bus while being connected to the grid."; throw std::runtime_error(exc_.str()); } - // if(bus_id_solver == slack_bus_id_solver) continue; // slack bus is not PV + if(is_in_vect(bus_id_solver, slack_bus_id_solver)) continue; // slack bus is not PV if(has_bus_been_added[bus_id_solver]) continue; // i already added this bus bus_pv.push_back(bus_id_solver); @@ -199,6 +226,7 @@ void DataGen::get_vm_for_dc(RealVect & Vm){ // i don't do anything if the generator is disconnected if(!status_[gen_id]) continue; + if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv bus_id_me = bus_id_(gen_id); @@ -232,6 +260,23 @@ void DataGen::change_p(int gen_id, real_type new_p, bool & need_reset) p_mw_(gen_id) = new_p; } +void DataGen::change_q(int gen_id, real_type new_q, bool & need_reset) +{ + 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_ << "DataGen::change_q: Impossible to change the reactive value 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 + q_mvar_(gen_id) = new_q; +} + void DataGen::change_v(int gen_id, real_type new_v_pu, bool & need_reset) { bool my_status = status_.at(gen_id); // and this check that load_id is not out of bound @@ -255,6 +300,7 @@ void DataGen::set_vm(CplxVect & V, const std::vector & id_grid_to_solver) c // i don't do anything if the generator is disconnected if(!status_[gen_id]) continue; + if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv bus_id_me = bus_id_(gen_id); @@ -329,6 +375,7 @@ void DataGen::init_q_vector(int nb_bus, { if(!status_[gen_id]) continue; + if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv int bus_id = bus_id_(gen_id); @@ -354,6 +401,7 @@ void DataGen::set_q(const RealVect & reactive_mismatch, real_type real_q = 0.; if(!status_[gen_id]) continue; // set at 0 for disconnected generators + if (!voltage_regulator_on_[gen_id]) continue; // gen is purposedly not pv if ((!turnedoff_gen_pv_) && p_mw_(gen_id) == 0.) continue; // in this case turned off generators are not pv int bus_id = bus_id_(gen_id); diff --git a/src/DataGen.h b/src/DataGen.h index d125bf2..ae72d3d 100644 --- a/src/DataGen.h +++ b/src/DataGen.h @@ -45,8 +45,10 @@ class DataGen: public DataGeneric bool is_slack; real_type slack_weight; + bool voltage_regulator_on; real_type target_p_mw; real_type target_vm_pu; + real_type target_q_mvar; real_type min_q_mvar; real_type max_q_mvar; bool has_res; @@ -62,8 +64,10 @@ class DataGen: public DataGeneric bus_id(-1), is_slack(false), slack_weight(-1.0), + voltage_regulator_on(false), target_p_mw(0.), target_vm_pu(0.), + target_q_mvar(0.), min_q_mvar(0.), max_q_mvar(0.), has_res(false), @@ -83,8 +87,10 @@ class DataGen: public DataGeneric is_slack = r_data_gen.gen_slackbus_[my_id]; slack_weight = r_data_gen.gen_slack_weight_[my_id]; + voltage_regulator_on = r_data_gen.voltage_regulator_on_[my_id]; target_p_mw = r_data_gen.p_mw_.coeff(my_id); target_vm_pu = r_data_gen.vm_pu_.coeff(my_id); + target_q_mvar = r_data_gen.q_mvar_.coeff(my_id); min_q_mvar = r_data_gen.min_q_.coeff(my_id); max_q_mvar = r_data_gen.max_q_.coeff(my_id); @@ -108,8 +114,10 @@ class DataGen: public DataGeneric typedef std::tuple< std::vector, 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 @@ -129,6 +137,15 @@ class DataGen: public DataGeneric const Eigen::VectorXi & generators_bus_id ); + void 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 + ); + int nb() const { return static_cast(p_mw_.size()); } // iterator @@ -220,6 +237,7 @@ class DataGen: public DataGeneric 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, bool & need_reset); + void change_q(int gen_id, real_type new_q, bool & need_reset); void change_v(int gen_id, real_type new_v_pu, bool & need_reset); virtual void fillSbus(CplxVect & Sbus, const std::vector & id_grid_to_solver, bool ac) const; @@ -271,8 +289,10 @@ class DataGen: public DataGeneric // physical properties // 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_; diff --git a/src/GridModel.h b/src/GridModel.h index 28740fd..a4d31b8 100644 --- a/src/GridModel.h +++ b/src/GridModel.h @@ -181,6 +181,16 @@ class GridModel : public DataGeneric const Eigen::VectorXi & generators_bus_id){ generators_.init(generators_p, generators_v, generators_min_q, generators_max_q, generators_bus_id); } + void init_generators_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){ + generators_.init_full(generators_p, generators_v, generators_q, voltage_regulator_on, + generators_min_q, generators_max_q, generators_bus_id); + } void init_loads(const RealVect & loads_p, const RealVect & loads_q, const Eigen::VectorXi & loads_bus_id){ diff --git a/src/main.cpp b/src/main.cpp index 88221a8..a8f29e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -410,8 +410,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m) .def_readonly("bus_id", &DataGen::GenInfo::bus_id, DocIterator::bus_id.c_str()) .def_readonly("is_slack", &DataGen::GenInfo::is_slack, DocIterator::is_slack.c_str()) .def_readonly("slack_weight", &DataGen::GenInfo::slack_weight, DocIterator::slack_weight.c_str()) + .def_readonly("voltage_regulator_on", &DataGen::GenInfo::voltage_regulator_on, "TODO") .def_readonly("target_p_mw", &DataGen::GenInfo::target_p_mw, DocIterator::target_p_mw.c_str()) .def_readonly("target_vm_pu", &DataGen::GenInfo::target_vm_pu, DocIterator::target_vm_pu.c_str()) + .def_readonly("target_q_mvar", &DataGen::GenInfo::target_q_mvar, "TODO") .def_readonly("min_q_mvar", &DataGen::GenInfo::min_q_mvar, DocIterator::min_q_mvar.c_str()) .def_readonly("max_q_mvar", &DataGen::GenInfo::max_q_mvar, DocIterator::max_q_mvar.c_str()) .def_readonly("has_res", &DataGen::GenInfo::has_res, DocIterator::has_res.c_str()) @@ -642,6 +644,7 @@ PYBIND11_MODULE(lightsim2grid_cpp, m) .def("init_shunt", &GridModel::init_shunt, DocGridModel::_internal_do_not_use.c_str()) // same .def("init_trafo", &GridModel::init_trafo, DocGridModel::_internal_do_not_use.c_str()) // same .def("init_generators", &GridModel::init_generators, DocGridModel::_internal_do_not_use.c_str()) // same + .def("init_generators_full", &GridModel::init_generators_full, DocGridModel::_internal_do_not_use.c_str()) // same .def("init_loads", &GridModel::init_loads, DocGridModel::_internal_do_not_use.c_str()) // same .def("init_storages", &GridModel::init_storages, DocGridModel::_internal_do_not_use.c_str()) // same .def("init_sgens", &GridModel::init_sgens, DocGridModel::_internal_do_not_use.c_str()) // same