Skip to content

Commit

Permalink
small speed ups + fix a broken test in DC, load_p was not 0
Browse files Browse the repository at this point in the history
  • Loading branch information
BDonnot committed Mar 22, 2024
1 parent b808c01 commit 1a26d3f
Showing 19 changed files with 98 additions and 78 deletions.
99 changes: 37 additions & 62 deletions lightsim2grid/lightSimBackend.py
Original file line number Diff line number Diff line change
@@ -141,7 +141,8 @@ def __init__(self,
self._timer_postproc = 0.
self._timer_solver = 0.
self._timer_read_data_back = 0.
self._timer_test_read = 0.
self._timer_fetch_data_cpp = 0.
self._timer_apply_act = 0.

self.next_prod_p = None # this vector is updated with the action that will modify the environment
# it is done to keep track of the redispatching
@@ -187,6 +188,7 @@ def __init__(self,
self.sh_p = None
self.sh_q = None
self.sh_v = None
self.sh_theta = None
self.sh_bus = None

# voltage angle
@@ -222,7 +224,8 @@ def __init__(self,
self._timer_preproc = 0.
self._timer_solver = 0.
self._timer_read_data_back = 0.
self._timer_test_read = 0.
self._timer_fetch_data_cpp = 0.
self._timer_apply_act = 0.

# hack for the storage unit:
# in grid2op, for simplicity, I suppose that if a storage is alone on a busbar, and
@@ -291,25 +294,6 @@ def turnedoff_no_pv(self):
def turnedoff_pv(self):
self._turned_off_pv = True
self._grid.turnedoff_pv()

def _fill_theta(self):
tick = time.perf_counter()
# line_or_theta = np.empty(self.n_line)
self.line_or_theta[:self.__nb_powerline] = self._grid.get_lineor_theta()
self.line_or_theta[self.__nb_powerline:] = self._grid.get_trafohv_theta()

# line_ex_theta = np.empty(self.n_line)
self.line_ex_theta[:self.__nb_powerline] = self._grid.get_lineex_theta()
self.line_ex_theta[self.__nb_powerline:] = self._grid.get_trafolv_theta()

# line_or_theta = np.concatenate((self._grid.get_lineor_theta(), self._grid.get_trafohv_theta()))
# line_ex_theta = np.concatenate((self._grid.get_lineex_theta(), self._grid.get_trafolv_theta()))
self.load_theta[:] = self._grid.get_load_theta()
self.gen_theta[:] = self._grid.get_gen_theta()

if self.__has_storage:
self.storage_theta[:] = self._grid.get_storage_theta()
self._timer_read_data_back += time.perf_counter() - tick

def get_theta(self):
"""
@@ -852,6 +836,7 @@ def _aux_finish_setup_after_reading(self):
self.sh_p = np.full(cls.n_shunt, dtype=dt_float, fill_value=np.NaN).reshape(-1)
self.sh_q = np.full(cls.n_shunt, dtype=dt_float, fill_value=np.NaN).reshape(-1)
self.sh_v = np.full(cls.n_shunt, dtype=dt_float, fill_value=np.NaN).reshape(-1)
self.sh_theta = np.full(cls.n_shunt, dtype=dt_float, fill_value=np.NaN).reshape(-1)
self.sh_bus = np.full(cls.n_shunt, dtype=dt_int, fill_value=-1).reshape(-1)

self.p_or = np.full(cls.n_line, dtype=dt_float, fill_value=np.NaN).reshape(-1)
@@ -966,6 +951,7 @@ def apply_action(self, backendAction):
"""
Specific implementation of the method to apply an action modifying a powergrid in the pandapower format.
"""
tick = time.perf_counter()
active_bus, *_, topo__, shunts__ = backendAction()

# change the overall topology
@@ -1017,30 +1003,31 @@ def apply_action(self, backendAction):
self._grid.change_q_shunt(sh_id, new_q)

self._handle_dist_slack()

self._timer_apply_act += time.perf_counter() - tick

def _handle_dist_slack(self):
if self._dist_slack_non_renew:
self._grid.update_slack_weights(type(self).gen_redispatchable)

def _fetch_grid_data(self):
beg_test = time.perf_counter()
if self._lineor_res is None:
self._lineor_res = self._grid.get_lineor_res()
self._lineor_res = self._grid.get_lineor_res_full()
if self._lineex_res is None:
self._lineex_res = self._grid.get_lineex_res()
self._lineex_res = self._grid.get_lineex_res_full()
if self._load_res is None:
self._load_res = self._grid.get_loads_res()
self._load_res = self._grid.get_loads_res_full()
if self._gen_res is None:
self._gen_res = self._grid.get_gen_res()
self._gen_res = self._grid.get_gen_res_full()
if self._trafo_hv_res is None:
self._trafo_hv_res = self._grid.get_trafohv_res()
self._trafo_hv_res = self._grid.get_trafohv_res_full()
if self._trafo_lv_res is None:
self._trafo_lv_res = self._grid.get_trafolv_res()
self._trafo_lv_res = self._grid.get_trafolv_res_full()
if self._storage_res is None:
self._storage_res = self._grid.get_storages_res()
self._storage_res = self._grid.get_storages_res_full()
if self._shunt_res is None:
self._shunt_res = self._grid.get_shunts_res()
self._timer_test_read += time.perf_counter() - beg_test
self._shunt_res = self._grid.get_shunts_res_full()
self._timer_fetch_data_cpp += time.perf_counter() - beg_test

def runpf(self, is_dc=False):
my_exc_ = None
@@ -1103,19 +1090,23 @@ def runpf(self, is_dc=False):
(self.p_or[:self.__nb_powerline],
self.q_or[:self.__nb_powerline],
self.v_or[:self.__nb_powerline],
self.a_or[:self.__nb_powerline]) = self._lineor_res
self.a_or[:self.__nb_powerline],
self.line_or_theta[:self.__nb_powerline]) = self._lineor_res
(self.p_or[self.__nb_powerline:],
self.q_or[self.__nb_powerline:],
self.v_or[self.__nb_powerline:],
self.a_or[self.__nb_powerline:]) = self._trafo_hv_res
self.a_or[self.__nb_powerline:],
self.line_or_theta[self.__nb_powerline:]) = self._trafo_hv_res
(self.p_ex[:self.__nb_powerline],
self.q_ex[:self.__nb_powerline],
self.v_ex[:self.__nb_powerline],
self.a_ex[:self.__nb_powerline]) = self._lineex_res
self.a_ex[:self.__nb_powerline],
self.line_ex_theta[:self.__nb_powerline]) = self._lineex_res
(self.p_ex[self.__nb_powerline:],
self.q_ex[self.__nb_powerline:],
self.v_ex[self.__nb_powerline:],
self.a_ex[self.__nb_powerline:]) = self._trafo_lv_res
self.a_ex[self.__nb_powerline:],
self.line_ex_theta[self.__nb_powerline:]) = self._trafo_lv_res

self.a_or *= 1000. # kA in lightsim, A expected in grid2op
self.a_ex *= 1000. # kA in lightsim, A expected in grid2op
@@ -1125,10 +1116,10 @@ def runpf(self, is_dc=False):
self.a_ex[~np.isfinite(self.a_ex)] = 0.
self.v_ex[~np.isfinite(self.v_ex)] = 0.

self.load_p[:], self.load_q[:], self.load_v[:] = self._load_res
self.prod_p[:], self.prod_q[:], self.prod_v[:] = self._gen_res
self.load_p[:], self.load_q[:], self.load_v[:], self.load_theta[:] = self._load_res
self.prod_p[:], self.prod_q[:], self.prod_v[:], self.gen_theta[:] = self._gen_res
if self.__has_storage:
self.storage_p[:], self.storage_q[:], self.storage_v[:] = self._storage_res
self.storage_p[:], self.storage_q[:], self.storage_v[:], self.storage_theta[:] = self._storage_res
self.storage_v[self.storage_v == -1.] = 0. # voltage is 0. for disconnected elements in grid2op
self._timer_read_data_back += time.perf_counter() - beg_readback

@@ -1148,8 +1139,6 @@ def runpf(self, is_dc=False):

if type(self).shunts_data_available:
self._set_shunt_info()

self._fill_theta()

if (self.line_or_theta >= 1e6).any() or (self.line_ex_theta >= 1e6).any():
raise BackendError(f"Some theta are above 1e6 which should not be happening !")
@@ -1200,6 +1189,7 @@ def _fill_nans(self):
self.sh_p[:] = np.NaN
self.sh_q[:] = np.NaN
self.sh_v[:] = np.NaN
self.sh_theta[:] = np.NaN
self.sh_bus[:] = -1

if self.__has_storage:
@@ -1275,12 +1265,12 @@ def copy(self):
"_big_topo_to_obj", "dim_topo",
"_idx_hack_storage",
"_timer_preproc", "_timer_postproc", "_timer_solver",
"_timer_read_data_back",
"_timer_read_data_back", "_timer_apply_act",
"supported_grid_format",
"max_it", "tol", "_turned_off_pv", "_dist_slack_non_renew",
"_use_static_gen", "_loader_method", "_loader_kwargs",
"_stop_if_load_disco", "_stop_if_gen_disco",
"_timer_test_read"
"_timer_fetch_data_cpp"
]
for attr_nm in li_regular_attr:
if hasattr(self, attr_nm):
@@ -1298,7 +1288,7 @@ def copy(self):
"load_p", "load_q", "load_v",
"prod_p", "prod_q", "prod_v",
"storage_p", "storage_q", "storage_v",
"sh_p", "sh_q", "sh_v", "sh_bus",
"sh_p", "sh_q", "sh_v", "sh_bus", "sh_theta",
"line_or_theta", "line_ex_theta", "load_theta", "gen_theta", "storage_theta",
]
for attr_nm in li_attr_npy:
@@ -1409,26 +1399,10 @@ def _compute_shunt_bus_with_compat(self, shunt_bus):

def _set_shunt_info(self):
tick = time.perf_counter()
self.sh_p[:], self.sh_q[:], self.sh_v[:] = self._shunt_res
# cls = type(self)
# shunt_bus = np.array([self._grid.get_bus_shunt(i) for i in range(cls.n_shunt)], dtype=dt_int)
# shunt_bus = self._grid.get_all_shunt_buses()
# if hasattr(cls, "global_bus_to_local"):
# self.sh_bus[:] = cls.global_bus_to_local(shunt_bus, cls.shunt_to_subid)
# else:
# res = (1 * shunt_bus).astype(dt_int) # make a copy
# if hasattr(cls, "n_busbar_per_sub"):
# n_busbar_per_sub = cls.n_busbar_per_sub
# else:
# # backward compat when this was not defined:
# n_busbar_per_sub = DEFAULT_N_BUSBAR_PER_SUB
# for i in range(n_busbar_per_sub):
# res[(i * cls.n_sub <= shunt_bus) & (shunt_bus < (i+1) * cls.n_sub)] = i + 1
# res[shunt_bus == -1] = -1
# self.sh_bus[:] = res
self.sh_p[:], self.sh_q[:], self.sh_v[:], self.sh_theta[:] = self._shunt_res
self.sh_v[self.sh_v == -1.] = 0. # in grid2op disco element have voltage of 0. and -1.
self._timer_read_data_back += time.perf_counter() - tick
# self._timer_test_read += time.perf_counter() - tick
# self._timer_fetch_data_cpp += time.perf_counter() - tick

def _disconnect_line(self, id_):
self.topo_vect[self.line_ex_pos_topo_vect[id_]] = -1
@@ -1453,7 +1427,8 @@ def reset(self, grid_path, grid_filename=None):
self._timer_preproc = 0.
self._timer_solver = 0.
self._timer_read_data_back = 0.
self._timer_test_read = 0.
self._timer_fetch_data_cpp = 0.
self._timer_apply_act = 0.
self._grid.tell_solver_need_reset()
self.sh_bus[:] = 1 # TODO self._compute_shunt_bus_with_compat(self._grid.get_all_shunt_buses())
self.topo_vect[:] = self.__init_topo_vect # TODO
5 changes: 3 additions & 2 deletions lightsim2grid/tests/test_DCPF.py
Original file line number Diff line number Diff line change
@@ -196,8 +196,9 @@ def _aux_test(self, pn_net):
load_p, load_q, load_v = backend.loads_info()
max_mis = np.max(np.abs(load_p - load_p_pp))
assert max_mis <= self.tol, f"Error: load_p do not match, maximum absolute error is {max_mis:.5f} MW"
max_mis = np.max(np.abs(load_q - load_q_pp))
assert max_mis <= self.tol, f"Error: load_q do not match, maximum absolute error is {max_mis:.5f} MVAr"
# PP does not set "load_q" to 0. in DC
# max_mis = np.max(np.abs(load_q - load_q_pp))
# assert max_mis <= self.tol, f"Error: load_q do not match, maximum absolute error is {max_mis:.5f} MVAr"
max_mis = np.max(np.abs(load_v - load_v_pp))
assert max_mis <= self.tol, f"Error: load_v do not match, maximum absolute error is {max_mis:.5f} kV"

1 change: 1 addition & 0 deletions src/BaseConstants.cpp
Original file line number Diff line number Diff line change
@@ -14,3 +14,4 @@ const real_type BaseConstants::my_one_ = 1.0;
const real_type BaseConstants::my_two_ = 2.0;
const real_type BaseConstants::my_half_ = 0.5;
const real_type BaseConstants::my_zero_ = 0.;
const real_type BaseConstants::my_180_pi_ = 180. / M_PI;
1 change: 1 addition & 0 deletions src/BaseConstants.h
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ class BaseConstants
static const real_type my_one_;
static const real_type my_two_;
static const real_type my_zero_;
static const real_type my_180_pi_;
};

enum class FDPFMethod {XB, BX}; // Different type of FDPF powerflow
13 changes: 13 additions & 0 deletions src/GridModel.h
Original file line number Diff line number Diff line change
@@ -496,6 +496,19 @@ class GridModel : public GenericContainer

Eigen::Ref<const IntVect> get_all_shunt_buses() const {return shunts_.get_buses();}

// complete results (with theta)
tuple4d get_loads_res_full() const {return loads_.get_res_full();}
tuple4d get_shunts_res_full() const {return shunts_.get_res_full();}
tuple4d get_gen_res_full() const {return generators_.get_res_full();}
tuple5d get_lineor_res_full() const {return powerlines_.get_res_or_full();}
tuple5d get_lineex_res_full() const {return powerlines_.get_res_ex_full();}
tuple5d get_trafohv_res_full() const {return trafos_.get_res_hv_full();}
tuple5d get_trafolv_res_full() const {return trafos_.get_res_lv_full();}
tuple4d get_storages_res_full() const {return storages_.get_res_full();}
tuple4d get_sgens_res_full() const {return sgens_.get_res_full();}
tuple4d get_dclineor_res_full() const {return dc_lines_.get_res_or_full();}
tuple4d get_dclineex_res_full() const {return dc_lines_.get_res_ex_full();}

// get some internal information, be cerafull the ID of the buses might not be the same
// TODO convert it back to this ID, that will make copies, but who really cares ?
Eigen::SparseMatrix<cplx_type> get_Ybus(){
12 changes: 9 additions & 3 deletions src/Utils.h
Original file line number Diff line number Diff line change
@@ -22,16 +22,22 @@ typedef double real_type; // type for real numbers: can be changed if installed
typedef std::complex<real_type> cplx_type; // type for complex number

typedef Eigen::Matrix<real_type, Eigen::Dynamic, 1> EigenPythonNumType; // Eigen::VectorXd
typedef Eigen::Matrix<int, Eigen::Dynamic, 1> IntVect;
typedef Eigen::Matrix<real_type, Eigen::Dynamic, 1> RealVect;
typedef Eigen::Matrix<cplx_type, Eigen::Dynamic, 1> CplxVect;

typedef std::tuple<Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType> > tuple3d;
typedef std::tuple<Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType> > tuple4d;
typedef Eigen::Matrix<int, Eigen::Dynamic, 1> IntVect;
typedef Eigen::Matrix<real_type, Eigen::Dynamic, 1> RealVect;
typedef Eigen::Matrix<cplx_type, Eigen::Dynamic, 1> CplxVect;
typedef std::tuple<Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType>,
Eigen::Ref<const EigenPythonNumType> > tuple5d;

typedef Eigen::Matrix<real_type, Eigen::Dynamic, Eigen::Dynamic> RealMat;
typedef Eigen::Matrix<cplx_type, Eigen::Dynamic, Eigen::Dynamic> CplxMat;
3 changes: 3 additions & 0 deletions src/element_container/DCLineContainer.h
Original file line number Diff line number Diff line change
@@ -294,6 +294,9 @@ class DCLineContainer : public GenericContainer

tuple3d get_or_res() const {return from_gen_.get_res();}
tuple3d get_ex_res() const {return to_gen_.get_res();}
tuple4d get_res_or_full() const {return from_gen_.get_res_full();}
tuple4d get_res_ex_full() const {return to_gen_.get_res_full();}

Eigen::Ref<const RealVect> get_theta_or() const {return from_gen_.get_theta();}
Eigen::Ref<const RealVect> get_theta_ex() const {return to_gen_.get_theta();}

1 change: 1 addition & 0 deletions src/element_container/GeneratorContainer.h
Original file line number Diff line number Diff line change
@@ -324,6 +324,7 @@ class GeneratorContainer: public GenericContainer
virtual void gen_p_per_bus(std::vector<real_type> & 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<const RealVect> get_theta() const {return res_theta_;}

const std::vector<bool>& get_status() const {return status_;}
2 changes: 1 addition & 1 deletion src/element_container/GenericContainer.cpp
Original file line number Diff line number Diff line change
@@ -162,6 +162,6 @@ void GenericContainer::v_deg_from_va(const Eigen::Ref<const RealVect> & Va,
exc_ << " is connected to a disconnected bus";
throw std::runtime_error(exc_.str());
}
theta(el_id) = Va(bus_solver_id) * 180. / my_pi;
theta(el_id) = Va(bus_solver_id) * my_180_pi_;
}
}
4 changes: 2 additions & 2 deletions src/element_container/LineContainer.cpp
Original file line number Diff line number Diff line change
@@ -426,8 +426,8 @@ void LineContainer::compute_results(const Eigen::Ref<const RealVect> & Va,
res_powerline_vex_(line_id) = v_ex * bus_vn_kv_ex;

// retrieve the voltage angle in degree (instead of radian)
res_powerline_thetaor_(line_id) = Va(bus_or_solver_id) * 180. / my_pi;
res_powerline_thetaex_(line_id) = Va(bus_ex_solver_id) * 180. / my_pi;
res_powerline_thetaor_(line_id) = Va(bus_or_solver_id) * my_180_pi_;
res_powerline_thetaex_(line_id) = Va(bus_ex_solver_id) * my_180_pi_;

// results of the powerflow
cplx_type Eor = V(bus_or_solver_id);
3 changes: 2 additions & 1 deletion src/element_container/LineContainer.h
Original file line number Diff line number Diff line change
@@ -247,7 +247,8 @@ class LineContainer : public GenericContainer

tuple4d get_lineor_res() const {return tuple4d(res_powerline_por_, res_powerline_qor_, res_powerline_vor_, res_powerline_aor_);}
tuple4d get_lineex_res() const {return tuple4d(res_powerline_pex_, res_powerline_qex_, res_powerline_vex_, res_powerline_aex_);}

tuple5d get_res_or_full() const {return tuple5d(res_powerline_por_, res_powerline_qor_, res_powerline_vor_, res_powerline_aor_, res_powerline_thetaor_);}
tuple5d get_res_ex_full() const {return tuple5d(res_powerline_pex_, res_powerline_qex_, res_powerline_vex_, res_powerline_aex_, res_powerline_thetaex_);}
Eigen::Ref<const RealVect> get_theta_or() const {return res_powerline_thetaor_;}
Eigen::Ref<const RealVect> get_theta_ex() const {return res_powerline_thetaex_;}
const std::vector<bool>& get_status() const {return status_;}
2 changes: 0 additions & 2 deletions src/element_container/LoadContainer.cpp
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ void LoadContainer::init(const RealVect & loads_p,
reset_results();
}


LoadContainer::StateRes LoadContainer::get_state() const
{
std::vector<real_type> p_mw(p_mw_.begin(), p_mw_.end());
@@ -54,7 +53,6 @@ void LoadContainer::set_state(LoadContainer::StateRes & my_state )
reset_results();
}


void LoadContainer::fillSbus(CplxVect & Sbus,
const std::vector<int> & id_grid_to_solver,
bool ac) const
2 changes: 2 additions & 0 deletions src/element_container/LoadContainer.h
Original file line number Diff line number Diff line change
@@ -177,6 +177,8 @@ class LoadContainer : public GenericContainer
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<const RealVect> get_theta() const {return res_theta_;}
const std::vector<bool>& get_status() const {return status_;}
const Eigen::VectorXi & get_bus_id() const {return bus_id_;}
1 change: 1 addition & 0 deletions src/element_container/SGenContainer.h
Original file line number Diff line number Diff line change
@@ -198,6 +198,7 @@ class SGenContainer: public GenericContainer
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<const RealVect> get_theta() const {return res_theta_;}
const std::vector<bool>& get_status() const {return status_;}
const Eigen::VectorXi & get_bus_id() const {return bus_id_;}
Loading

0 comments on commit 1a26d3f

Please sign in to comment.