diff --git a/src/pex/pex/pexRExtractor.cc b/src/pex/pex/pexRExtractor.cc index 02b5dbf59..11c36c771 100644 --- a/src/pex/pex/pexRExtractor.cc +++ b/src/pex/pex/pexRExtractor.cc @@ -138,7 +138,7 @@ RNetwork::create_node (RNode::node_type type, unsigned int port_index) } RElement * -RNetwork::create_element (double conductivity, RNode *a, RNode *b) +RNetwork::create_element (double conductance, RNode *a, RNode *b) { std::pair key (a, b); if (size_t (b) < size_t (a)) { @@ -148,17 +148,17 @@ RNetwork::create_element (double conductivity, RNode *a, RNode *b) auto i = m_elements_by_nodes.find (key); if (i != m_elements_by_nodes.end ()) { - if (conductivity == pex::RElement::short_value () || i->second->conductivity == pex::RElement::short_value ()) { - i->second->conductivity = pex::RElement::short_value (); + if (conductance == pex::RElement::short_value () || i->second->conductance == pex::RElement::short_value ()) { + i->second->conductance = pex::RElement::short_value (); } else { - i->second->conductivity += conductivity; + i->second->conductance += conductance; } return i->second; } else { - RElement *element = new RElement (this, conductivity, a, b); + RElement *element = new RElement (this, conductance, a, b); m_elements.push_back (element); m_elements_by_nodes.insert (std::make_pair (key, element)); @@ -204,7 +204,7 @@ RNetwork::join_nodes (RNode *a, RNode *b) for (auto e = b->elements ().begin (); e != b->elements ().end (); ++e) { RNode *on = const_cast ((*e)->other (b)); if (on != a) { - create_element ((*e)->conductivity, on, a); + create_element ((*e)->conductance, on, a); } } @@ -225,7 +225,7 @@ RNetwork::simplify () tl::equivalence_clusters clusters; for (auto e = m_elements.begin (); e != m_elements.end (); ++e) { - if (e->conductivity == pex::RElement::short_value () && (e->a ()->type == pex::RNode::Internal || e->b ()->type == pex::RNode::Internal)) { + if (e->conductance == pex::RElement::short_value () && (e->a ()->type == pex::RNode::Internal || e->b ()->type == pex::RNode::Internal)) { clusters.same (e->a (), e->b ()); } } diff --git a/src/pex/pex/pexRExtractor.h b/src/pex/pex/pexRExtractor.h index 11e05e00d..0e7a2578e 100644 --- a/src/pex/pex/pexRExtractor.h +++ b/src/pex/pex/pexRExtractor.h @@ -40,25 +40,57 @@ class RElement; class RNode; class RNetwork; +/** + * @brief Represents a node in the R graph + * + * A node connects to multiple elements (resistors). + * Every element has two nodes. The nodes and elements form + * a graph. + * + * RNode object cannot be created directly. Use "create_node" + * from RNetwork. + */ struct PEX_PUBLIC RNode : public tl::list_node { public: + /** + * @brief The type of the node + */ enum node_type { - Internal, - VertexPort, - PolygonPort + Internal, // an internal node, not related to a port + VertexPort, // a node related to a vertex port + PolygonPort // a node related to a polygon port }; + /** + * @brief The node type + */ node_type type; + + /** + * @brief The location + extension of the node + */ db::DBox location; + + /** + * @brief An index locating the node in the vertex or polygon port lists + * + * For internal nodes, the index is a unique numbers. + */ unsigned int port_index; + /** + * @brief Gets the R elements connected to this node + */ const std::list &elements () const { return m_elements; } + /** + * @brief Returns a string representation of the node + */ std::string to_string () const; protected: @@ -80,14 +112,35 @@ private: mutable std::list m_elements; }; +/** + * @brief Represents an R element in the graph (an edge) + * + * An element has two nodes that form the ends of the edge and + * a conductance value (given in Siemens). + * + * The value can be RElement::short_value() indicating + * "infinite" conductance (a short). + * + * RElement objects cannot be created directly. Use "create_element" + * from RNetwork. + */ struct PEX_PUBLIC RElement : public tl::list_node { - double conductivity; + /** + * @brief The conductance value + */ + double conductance; + /** + * @brief The nodes the resistor connects + */ const RNode *a () const { return mp_a; } const RNode *b () const { return mp_b; } + /** + * @brief Gets the other node for n + */ const RNode *other (const RNode *n) const { if (mp_a == n) { @@ -98,16 +151,27 @@ struct PEX_PUBLIC RElement tl_assert (false); } + /** + * @brief Represents the conductance value for a short + */ static double short_value () { return std::numeric_limits::infinity (); } + /** + * @brief Gets the resistance value + * + * The resistance value is the inverse of the conducance. + */ double resistance () const { - return conductivity == short_value () ? 0.0 : 1.0 / conductivity; + return conductance == short_value () ? 0.0 : 1.0 / conductance; } + /** + * @brief Returns a string representation of the element + */ std::string to_string () const; protected: @@ -115,7 +179,7 @@ protected: friend class tl::list_impl; RElement (RNetwork *network, double _conductivity, const RNode *a, const RNode *b) - : conductivity (_conductivity), mp_network (network), mp_a (a), mp_b (b) + : conductance (_conductivity), mp_network (network), mp_a (a), mp_b (b) { } ~RElement () @@ -138,6 +202,9 @@ private: RElement &operator= (const RElement &other); }; +/** + * @brief Represents a R network (a graph of RNode and RElement) + */ class PEX_PUBLIC RNetwork : public tl::Object { @@ -147,33 +214,95 @@ public: typedef tl::list element_list; typedef element_list::const_iterator element_iterator; + /** + * @brief Constructor + */ RNetwork (); + + /** + * @brief Destructor + */ ~RNetwork (); + /** + * @brief Creates a node with the given type and port index + * + * If the node type is Internal, a new node is created always. + * If the node type is VertexPort or PolygonPort, an existing + * node is returned if one way created with the same type + * or port index already. This avoids creating duplicates + * for the same port. + */ RNode *create_node (RNode::node_type type, unsigned int port_index); - RElement *create_element (double conductivity, RNode *a, RNode *b); + + /** + * @brief Creates a new element between the given nodes + * + * If an element already exists between the specified nodes, the + * given value is added to the existing element and the existing + * object is returned. + */ + RElement *create_element (double conductance, RNode *a, RNode *b); + + /** + * @brief Removes the given element + * + * Removing the element will also remove any orphan nodes + * at the ends if they are of type Internal. + */ void remove_element (RElement *element); + + /** + * @brief Removes the node and the attached elements. + * + * Only nodes of type Internal can be removed. + */ void remove_node (RNode *node); + + /** + * @brief Clears the network + */ void clear (); + + /** + * @brief Simplifies the network + * + * This will: + * - Join serial resistors if connected by an internal node + * - Remove shorts and join the nodes, if one of them is + * an internal node. The non-internal node will persist. + * - Remove "dangling" resistors if the dangling node is + * an internal one + */ void simplify (); - std::string to_string () const; - + /** + * @brief Iterate the nodes (begin) + */ node_iterator begin_nodes () const { return m_nodes.begin (); } + /** + * @brief Iterate the nodes (end) + */ node_iterator end_nodes () const { return m_nodes.end (); } + /** + * @brief Gets the number of nodes + */ size_t num_nodes () const { return m_nodes.size (); } + /** + * @brief Gets the number of internal nodes + */ size_t num_internal_nodes () const { size_t count = 0; @@ -185,21 +314,35 @@ public: return count; } + /** + * @brief Iterate the elements (begin) + */ element_iterator begin_elements () const { return m_elements.begin (); } + /** + * @brief Iterate the elements (end) + */ element_iterator end_elements () const { return m_elements.end (); } + /** + * @brief Gets the number of elements + */ size_t num_elements () const { return m_elements.size (); } + /** + * @brief Returns a string representation of the graph + */ + std::string to_string () const; + private: node_list m_nodes; element_list m_elements; @@ -225,9 +368,24 @@ private: class PEX_PUBLIC RExtractor { public: + /** + * @brief Constructor + */ RExtractor (); + + /** + * @brief Destructor + */ virtual ~RExtractor (); + /** + * @brief Extracts the resistance network from the given polygon and ports + * + * The ports define specific locations where to connect to the resistance network. + * The network will contain corresponding nodes with the VertexPort for vertex ports + * and PolygonPort for polygon port. The node index is the index in the respective + * lists. + */ virtual void extract (const db::Polygon &polygon, const std::vector &vertex_ports, const std::vector &polygon_ports, RNetwork &rnetwork) = 0; }; diff --git a/src/pex/pex/pexSquareCountingRExtractor.cc b/src/pex/pex/pexSquareCountingRExtractor.cc index de6400491..97a96c1d1 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.cc +++ b/src/pex/pex/pexSquareCountingRExtractor.cc @@ -165,7 +165,6 @@ SquareCountingRExtractor::do_extract (const db::Polygon &db_poly, const std::vec // @@@ TODO: multiply with sheet rho! // @@@ TODO: width dependency if (r == 0) { - // @@@ TODO: join nodes later! rnetwork.create_element (pex::RElement::short_value (), pl->second, pl_next->second); } else { rnetwork.create_element (r, pl->second, pl_next->second); @@ -293,6 +292,7 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector } + rnetwork.simplify (); } } diff --git a/src/pex/pex/pexSquareCountingRExtractor.h b/src/pex/pex/pexSquareCountingRExtractor.h index abacc2dfa..9ceb99d46 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.h +++ b/src/pex/pex/pexSquareCountingRExtractor.h @@ -31,28 +31,58 @@ namespace pex { -// @@@ doc +/** + * @brief The Square Counting R Extractor + * + * The idea of that extractor is to first decompose the polygon into + * convex parts. Each convex part is taken as "thin" and the current + * flow being parallel and homogeneous to the long axis. + * + * Internal ports are created between the partial polygons where + * they touch. + * + * The ports are considered point-like (polygon ports are replaced + * by points in their bounding box centers) and inject current + * at their specific position only. The resistance is accumulated + * between ports by integrating the squares (length along + * the long axis / width). + */ class PEX_PUBLIC SquareCountingRExtractor : public RExtractor { public: + /** + * @brief The constructor + */ SquareCountingRExtractor (double dbu); + /** + * @brief Gets the decomposition parameters + */ db::plc::ConvexDecompositionParameters &decomposition_parameters () { return m_decomp_param; } + /** + * @brief Sets the database unit + */ void set_dbu (double dbu) { m_dbu = dbu; } + /** + * @brief Gets the database unit + */ double dbu () const { return m_dbu; } + /** + * @brief Implementation of the extraction function + */ virtual void extract (const db::Polygon &polygon, const std::vector &vertex_ports, const std::vector &polygon_ports, RNetwork &rnetwork); protected: diff --git a/src/pex/pex/pexTriangulationRExtractor.cc b/src/pex/pex/pexTriangulationRExtractor.cc index 5a7a87047..fabc3789e 100644 --- a/src/pex/pex/pexTriangulationRExtractor.cc +++ b/src/pex/pex/pexTriangulationRExtractor.cc @@ -301,7 +301,7 @@ TriangulationRExtractor::eliminate_node (pex::RNode *node, RNetwork &rnetwork) { double s_sum = 0.0; for (auto e = node->elements ().begin (); e != node->elements ().end (); ++e) { - s_sum += (*e)->conductivity; + s_sum += (*e)->conductance; } if (fabs (s_sum) > 1e-10) { @@ -311,7 +311,7 @@ TriangulationRExtractor::eliminate_node (pex::RNode *node, RNetwork &rnetwork) for ( ; ee != node->elements ().end (); ++ee) { pex::RNode *n1 = const_cast ((*e)->other (node)); pex::RNode *n2 = const_cast ((*ee)->other (node)); - double c = (*e)->conductivity * (*ee)->conductivity / s_sum; + double c = (*e)->conductance * (*ee)->conductance / s_sum; rnetwork.create_element (c, n1, n2); } } diff --git a/src/pex/pex/pexTriangulationRExtractor.h b/src/pex/pex/pexTriangulationRExtractor.h index 536d90f45..4215d0180 100644 --- a/src/pex/pex/pexTriangulationRExtractor.h +++ b/src/pex/pex/pexTriangulationRExtractor.h @@ -31,28 +31,59 @@ namespace pex { -// @@@ doc +/** + * @brief An R extractor based on a triangulation of the resistor area + * + * This resistor extractor starts with a triangulation of the + * polygon area and substitutes each triangle by a 3-resistor network. + * + * After this, it will eliminate nodes where possible. + * + * This extractor delivers a resistor matrix (there is a resistor + * between every specified port). + * + * Polygon ports are considered to be perfectly conductive and cover + * their given area, shorting all nodes at their boundary. + * + * This extractor delivers higher quality results than the square + * counting extractor, but is slower in general. + */ class PEX_PUBLIC TriangulationRExtractor : public RExtractor { public: + /** + * @brief The constructor + */ TriangulationRExtractor (double dbu); + /** + * @brief Gets the triangulation parameters + */ db::plc::TriangulationParameters &triangulation_parameters () { return m_tri_param; } + /** + * @brief Sets the database unit + */ void set_dbu (double dbu) { m_dbu = dbu; } + /** + * @brief Gets the database unit + */ double dbu () const { return m_dbu; } + /** + * @brief Implementation of the extraction function + */ virtual void extract (const db::Polygon &polygon, const std::vector &vertex_ports, const std::vector &polygon_ports, RNetwork &rnetwork); private: