Doc and small fixes

This commit is contained in:
Matthias Koefferlein 2025-04-20 21:52:44 +02:00
parent 9bf03390de
commit 93e10d1d72
6 changed files with 240 additions and 21 deletions

View File

@ -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<RNode *, RNode *> 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<RNode *> ((*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<const RNode *> 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 ());
}
}

View File

@ -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<RNode>
{
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<const RElement *> &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<const RElement *> 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<RElement>
{
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<double>::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, false>;
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<RElement, false> 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<db::Point> &vertex_ports, const std::vector<db::Polygon> &polygon_ports, RNetwork &rnetwork) = 0;
};

View File

@ -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 ();
}
}

View File

@ -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<db::Point> &vertex_ports, const std::vector<db::Polygon> &polygon_ports, RNetwork &rnetwork);
protected:

View File

@ -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 <pex::RNode *> ((*e)->other (node));
pex::RNode *n2 = const_cast <pex::RNode *> ((*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);
}
}

View File

@ -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<db::Point> &vertex_ports, const std::vector<db::Polygon> &polygon_ports, RNetwork &rnetwork);
private: