This repository has been archived on 2018-12-13. You can view files and clone it, but cannot push or open issues or pull requests.
arma-flow/src/calc.hpp

328 lines
7.8 KiB
C++

//
// arma-flow/calc.hpp
//
// @author CismonX
//
#pragma once
#include <armadillo>
#include <vector>
namespace flow
{
/// Power flow calculation.
class calc
{
/// Structure of node data.
struct node_data
{
/// Node ID.
unsigned id;
/// Voltage (real);
double v;
/// Generator (active power)
double g;
/// Load (active power)
double p;
/// Load (reactive power)
double q;
/// Generator admittance
double x_d;
/// Node type.
enum node_type {
pq, pv, swing
} type;
};
/// Structure of edge data.
struct edge_data
{
/// First and second node ID.
unsigned m, n;
/// Resistance (real).
double r;
/// Resistance (imaginary).
double x;
/// Grounding admittance (imaginary).
double b;
/// Transformer ratio.
double k;
/**
* Get admittance of edge.
*
* @return Admittance (complex).
*/
std::complex<double> admittance() const
{
const auto deno = r * r + x * x;
return { r / deno, -x / deno };
}
/**
* Get impedance of edge.
*
* @return Admittance (complex).
*/
std::complex<double> impedance() const
{
return { r, x };
}
/**
* Get grounding admittance.
*
* @return Grounding admittance (complex).
*/
std::complex<double> grounding_admittance() const
{
return { 0, b };
};
};
/// Vector of nodes.
std::vector<node_data> nodes_;
/// Number of nodes.
unsigned num_nodes_ = 0;
/// Number of PQ nodes and PV nodes.
unsigned num_pq_ = 0, num_pv_ = 0;
/// Vector of edges.
std::vector<edge_data> edges_;
/// Adjacency matrix of nodes.
arma::uchar_mat adj_;
/// Node admittance matrix.
arma::cx_mat n_adm_;
/// Node admittance matrix in original node order.
arma::cx_mat n_adm_orig_;
/// Node admittance matrix.
arma::mat n_adm_g_, n_adm_b_;
/// Node impedance matrix.
arma::cx_mat n_imp_;
/// Node impedance matrix.
arma::mat n_imp_g_, n_imp_b_;
/// Given values of power and voltage.
arma::colvec init_p_, init_q_, init_v_;
/// Correction vector of voltage.
arma::colvec e_, f_;
/// Imbalance of active/reactive power and voltage.
arma::colvec delta_p_, delta_q_, delta_v_;
/// Submatrix of Jacobian matrix.
arma::mat j_h_, j_n_, j_m_, j_l_, j_r_, j_s_;
/// F(x) of jacobian matrix.
arma::colvec f_x_;
/// Jacobian matrix (sparse).
arma::sp_mat j_;
/// Power vector of nodes.
arma::colvec p_, q_;
/// Voltage of nodes.
arma::colvec v_;
/// Whether to calculate short circuit.
bool short_circuit_;
/// Whether to ignore load current when calculating short circuit.
bool ignore_load_;
/// Node ID of three-phase short circuit.
unsigned short_circuit_node_;
/// Transition impedance of node.
std::complex<double> z_f_;
/// Value of short circuit current.
std::complex<double> i_f_;
/// Vector of short circuit voltage.
arma::cx_colvec u_f_;
/// Whether verbose output is enabled.
bool verbose_;
/// Max deviation to be tolerated.
double epsilon_ = 0;
/// Number of iterations.
unsigned n_iter_ = 1;
/**
* Get offset of sorted node by ID.
*
* @param id Node ID.
* @return Node offset.
*/
unsigned node_offset(unsigned id) const;
/// G(i, j) * e(i) + B(i, j) * f(i)
double j_elem_g_b(unsigned row, unsigned col) const;
/// B(i, j) * e(i) - G(i, j) * f(i)
double j_elem_b_g(unsigned row, unsigned col) const;
/// G(i, i) * e(i) + B(i, i) * f(i)
double j_elem_b(unsigned row) const
{
return j_elem_g_b(row, row);
}
/// B(i, i) * e(i) - G(i, i) * f(i)
double j_elem_d(unsigned row) const
{
return j_elem_b_g(row, row);
}
/// sum(i == j || adj(i, j), B(i, j) * f(j) - G(i, j) * e(j))
double j_elem_a(unsigned row) const;
/// sum(i == j || adj(i, j), G(i, j) * f(j) + B(i, j) * e(j))
double j_elem_c(unsigned row) const;
/**
* Traverse a matrix.
*
* @param mat Matrix to be traversed.
* @param func Callback for each element.
*/
template <typename M, typename F>
static void mat_elem_foreach(M& mat, F func)
{
for (auto row = 0U; row < mat.n_rows; ++row)
for (auto col = 0U; col < mat.n_cols; ++col)
func(mat.at(row, col), row, col);
}
/**
* Traverse a vector.
*
* @param vec Vector to be traversed.
* @param func Callback for each element
*/
template <typename V, typename F>
static void vec_elem_foreach(V& vec, F func)
{
for (auto i = 0U; i < vec.n_elem; ++i)
func(vec[i], i);
}
/**
* Update F(x) of jacobian matrix.
*/
void update_f_x();
/**
* Calculate jacobian matrix.
*/
void jacobian();
/**
* Prepare to solve the formula.
*/
void prepare_solve();
/// Calculate active power of a node.
double calc_p(unsigned row) const
{
return f_[row] * j_elem_c(row) - e_[row] * j_elem_a(row);
}
/// Calculate reactive power of a node.
double calc_q(unsigned row) const
{
return -f_[row] * j_elem_a(row) - e_[row] * j_elem_c(row);
}
/// Check whether a value is approximately zero.
bool approx_zero(double val) const
{
return std::abs(val) <= epsilon_;
}
public:
/**
* Default constructor.
*/
explicit calc() = default;
/**
* Initialize.
*/
void init(const arma::mat& nodes, const arma::mat& edges,
bool verbose, double epsilon, bool short_circuit, bool ignore_load,
unsigned short_circuit_node, const std::complex<double>& z_f);
/**
* Calculate node admittance.
*/
std::pair<arma::mat, arma::mat> node_admittance();
/**
* Calculate node impedance.
*/
std::pair<arma::mat, arma::mat> node_impedance();
/**
* Initialize iteration.
*/
void iterate_init();
/**
* Solve formula.
*
* @return number of iterations.
*/
unsigned solve();
/**
* Get max value of correction vector.
*/
double get_max() const;
/**
* Get result of power flow calculation.
*/
arma::mat result();
/**
* Get current of three-phase short circuit.
*/
std::complex<double> short_circuit_current();
/**
* Get node voltage of short circuit.
*/
arma::mat short_circuit_voltage();
/**
* Get edge current of short circuit.
*/
arma::mat short_circuit_edge_current();
};
}