GSI binding of RNetExtractor, introducing layers for nodes

This commit is contained in:
Matthias Koefferlein 2025-05-04 19:45:30 +02:00
parent fc25590dd7
commit 77aa729b06
14 changed files with 962 additions and 475 deletions

View File

@ -30,379 +30,6 @@
namespace gsi
{
class RNode
{
public:
~RNode () { }
pex::RNode::node_type type () const { return checked_pointer ()->type; }
db::DBox location () const { return checked_pointer ()->location; }
unsigned int port_index () const { return checked_pointer ()->port_index; }
std::string to_string (bool with_coords = false) const { return checked_pointer ()->to_string (with_coords); }
size_t obj_id () const
{
return size_t (mp_ptr);
}
static RNode *make_node_object (const pex::RNode *node)
{
return new RNode (node);
}
const pex::RNode *checked_pointer () const
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RNode object no longer is valid")));
}
return mp_ptr;
}
pex::RNode *checked_pointer ()
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RNode object no longer is valid")));
}
return const_cast<pex::RNode *> (mp_ptr);
}
private:
tl::weak_ptr<pex::RNetwork> mp_graph;
const pex::RNode *mp_ptr;
RNode (const pex::RNode *node)
: mp_graph (node->graph ()),
mp_ptr (node)
{
// .. nothing yet ..
}
};
class RElement
{
public:
~RElement () { }
double conductance () const { return checked_pointer ()->conductance; }
double resistance () const { return checked_pointer ()->resistance (); }
RNode *a () const { return RNode::make_node_object (checked_pointer ()->a ()); }
RNode *b () const { return RNode::make_node_object (checked_pointer ()->b ()); }
std::string to_string (bool with_coords = false) const { return checked_pointer ()->to_string (with_coords); }
size_t obj_id () const
{
return size_t (mp_ptr);
}
static RElement *make_element_object (const pex::RElement *element)
{
return new RElement (element);
}
const pex::RElement *checked_pointer () const
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RElement object no longer is valid")));
}
return mp_ptr;
}
pex::RElement *checked_pointer ()
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RElement object no longer is valid")));
}
return const_cast<pex::RElement *> (mp_ptr);
}
private:
tl::weak_ptr<pex::RNetwork> mp_graph;
const pex::RElement *mp_ptr;
RElement (const pex::RElement *node)
: mp_graph (node->graph ()),
mp_ptr (node)
{
// .. nothing yet ..
}
};
class RElementIterator
{
public:
typedef std::list<const pex::RElement *>::const_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RElement *value_type;
typedef RElement *reference;
typedef void pointer;
typedef void difference_type;
RElementIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const RElementIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RElement *operator* () const
{
return RElement::make_element_object (*m_it);
}
private:
basic_iter m_it;
};
static RElementIterator begin_node_elements (RNode *node)
{
return RElementIterator (node->checked_pointer ()->elements ().begin ());
}
static RElementIterator end_network_elements (RNode *node)
{
return RElementIterator (node->checked_pointer ()->elements ().end ());
}
gsi::Enum<pex::RNode::node_type> decl_NodeType ("pex", "RNodeType",
gsi::enum_const ("Internal", pex::RNode::Internal,
"@brief Specifies an internal node in a R network\n"
"Internal nodes are generated during the R extraction process. "
"The port index of such a node is an arbitrary index."
) +
gsi::enum_const ("VertexPort", pex::RNode::VertexPort,
"@brief Specifies a vertex port node in a R network\n"
"Vertex port nodes are generated for vertex ports in \\RExtractor#extract, see 'vertex_ports' argument. "
"The port index of such a node refers to the position in that list."
) +
gsi::enum_const ("PolygonPort", pex::RNode::PolygonPort,
"@brief Specifies a polygon port node in a R network\n"
"Polygon port nodes are generated for polygon ports in \\RExtractor#extract, see 'polygon_ports' argument. "
"The port index of such a node refers to the position in that list."
),
"@brief This class represents the node type for RNode.\n"
"\n"
"This class has been introduced in version 0.30.1"
);
Class<RNode> decl_RNode ("pex", "RNode",
gsi::method ("object_id", &RNode::obj_id,
"@brief Returns an ID representing the actual object\n"
"For every call, a new instance of this object is created, while multiple "
"ones may represent the same internal object. The 'object_id' is a ID that "
"indicates the internal object. Same object_id means same node."
) +
gsi::method ("to_s", &RNode::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of this object\n"
"Nodes are printed with coordinates with 'with_coords' is true."
) +
gsi::iterator_ext ("each_element", gsi::return_new_object (), &begin_node_elements, &end_network_elements,
"@brief Iterates the \\RElement objects attached to the node\n"
) +
gsi::method ("type", &RNode::type,
"@brief Gets the type attribute of the node\n"
) +
gsi::method ("location", &RNode::location,
"@brief Gets the location attribute of the node\n"
"The location defined the original position of the node"
) +
gsi::method ("port_index", &RNode::port_index,
"@brief Gets the port index of the node\n"
"The port index associates a node with a original port definition."
),
"@brief Represents a node in a R network graph\n"
"See \\RNetwork for a description of this object\n"
"\n"
"This class has been introduced in version 0.30.1"
);
// Inject the RNode::node_type declarations into RNode
gsi::ClassExt<RNode> inject_NodeType_in_RNode (decl_NodeType.defs ());
Class<RElement> decl_RElement ("pex", "RElement",
gsi::method ("object_id", &RElement::obj_id,
"@brief Returns an ID representing the actual object\n"
"For every call, a new instance of this object is created, while multiple "
"ones may represent the same internal object. The 'object_id' is a ID that "
"indicates the internal object. Same object_id means same element."
) +
gsi::method ("to_s", &RElement::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of this object\n"
"Nodes are printed with coordinates with 'with_coords' is true."
) +
gsi::method ("resistance", &RElement::resistance,
"@brief Gets the resistance value of the object\n"
) +
gsi::factory ("a", &RElement::a,
"@brief Gets the first node the element connects\n"
) +
gsi::factory ("b", &RElement::b,
"@brief Gets the second node the element connects\n"
),
"@brief Represents an edge (also called element) in a R network graph\n"
"See \\RNetwork for a description of this object"
"\n"
"This class has been introduced in version 0.30.1"
);
static RNode *create_node (pex::RNetwork *network, pex::RNode::node_type type, unsigned int port_index)
{
return RNode::make_node_object (network->create_node (type, port_index));
}
static RElement *create_element (pex::RNetwork *network, double r, RNode *a, RNode *b)
{
double s = fabs (r) < 1e-10 ? pex::RElement::short_value () : 1.0 / r;
return RElement::make_element_object (network->create_element (s, a->checked_pointer (), b->checked_pointer ()));
}
static void remove_element (pex::RNetwork *network, RElement *element)
{
network->remove_element (element->checked_pointer ());
}
static void remove_node (pex::RNetwork *network, RNode *node)
{
network->remove_node (node->checked_pointer ());
}
class NetworkElementIterator
{
public:
typedef pex::RNetwork::element_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RElement *value_type;
typedef RElement *reference;
typedef void pointer;
typedef void difference_type;
NetworkElementIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const NetworkElementIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RElement *operator* () const
{
return RElement::make_element_object (m_it.operator-> ());
}
private:
basic_iter m_it;
};
static NetworkElementIterator begin_network_elements (pex::RNetwork *network)
{
return NetworkElementIterator (network->begin_elements ());
}
static NetworkElementIterator end_network_elements (pex::RNetwork *network)
{
return NetworkElementIterator (network->end_elements ());
}
class NetworkNodeIterator
{
public:
typedef pex::RNetwork::node_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RNode *value_type;
typedef RNode *reference;
typedef void pointer;
typedef void difference_type;
NetworkNodeIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const NetworkNodeIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RNode *operator* () const
{
return RNode::make_node_object (m_it.operator-> ());
}
private:
basic_iter m_it;
};
static NetworkNodeIterator begin_network_nodes (pex::RNetwork *network)
{
return NetworkNodeIterator (network->begin_nodes ());
}
static NetworkNodeIterator end_network_nodes (pex::RNetwork *network)
{
return NetworkNodeIterator (network->end_nodes ());
}
Class<pex::RNetwork> decl_RNetwork ("pex", "RNetwork",
gsi::factory_ext ("create_node", &create_node, gsi::arg ("type"), gsi::arg ("port_index"),
"@brief Creates a new node with the given type and index'.\n"
"@return A reference to the new nbode object."
) +
gsi::factory_ext ("create_element", &create_element, gsi::arg ("resistance"), gsi::arg ("a"), gsi::arg ("b"),
"@brief Creates a new element between the nodes given by 'a' abd 'b'.\n"
"If a resistor already exists between the two nodes, both resistors are combined into one.\n"
"@return A reference to the new resistor object."
) +
gsi::method_ext ("remove_element", &remove_element, gsi::arg ("element"),
"@brief Removes the given element\n"
"If removing the element renders an internal node orphan (i.e. without elements), this "
"node is removed too."
) +
gsi::method_ext ("remove_node", &remove_node, gsi::arg ("node"),
"@brief Removes the given node\n"
"Only internal nodes can be removed. Removing a node will also remove the "
"elements attached to this node."
) +
gsi::method ("clear", &pex::RNetwork::clear,
"@brief Clears the network\n"
) +
gsi::method ("simplify", &pex::RNetwork::simplify,
"@brief Simplifies the network\n"
"\n"
"This will:\n"
"@ul\n"
"@li Join serial resistors if connected by an internal node @/li\n"
"@li Remove shorts and join the nodes, if one of them is\n"
" an internal node. The non-internal node will persist @/li\n"
"@li Remove \"dangling\" resistors if the dangling node is\n"
" an internal one @/li\n"
"@/ul\n"
) +
gsi::iterator_ext ("each_element", gsi::return_new_object (), &begin_network_elements, &end_network_elements,
"@brief Iterates the \\RElement objects inside the network\n"
) +
gsi::iterator_ext ("each_node", gsi::return_new_object (), &begin_network_nodes, &end_network_nodes,
"@brief Iterates the \\RNode objects inside the network\n"
) +
gsi::method ("num_nodes", &pex::RNetwork::num_nodes,
"@brief Gets the total number of nodes in the network\n"
) +
gsi::method ("num_internal_nodes", &pex::RNetwork::num_internal_nodes,
"@brief Gets the number of internal nodes in the network\n"
) +
gsi::method ("num_elements", &pex::RNetwork::num_elements,
"@brief Gets the number of elements in the network\n"
) +
gsi::method ("to_s", &pex::RNetwork::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of the network\n"
"Nodes are printed with coordinates with 'with_coords' is true."
),
"@brief Represents a network of resistors\n"
"\n"
"The network is basically a graph with nodes and edges (the resistors). "
"The resistors are called 'elements' and are represented by \\RElement objects. "
"The nodes are represented by \\RNode objects. "
"The network is created by \\RExtractor#extract, which turns a polygon into a resistor network.\n"
"\n"
"This class has been introduced in version 0.30.1\n"
);
static pex::RExtractor *new_sqc_rextractor (double dbu, bool skip_simplify)
{
auto res = new pex::SquareCountingRExtractor (dbu);
@ -490,7 +117,7 @@ Class<pex::RExtractor> decl_RExtractor ("pex", "RExtractor",
"Use \\tesselation_extractor and \\square_counting_extractor to create an actual extractor object.\n"
"To use the extractor, call the \\extract method on a given polygon with ports that define the network attachment points.\n"
"\n"
"This class has been introduced in version 0.30.1\n"
"This class has been introduced in version 0.30.2\n"
);
}

View File

@ -0,0 +1,393 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2025 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "gsiDecl.h"
#include "pexRExtractorTech.h"
#include "pexRNetExtractor.h"
#include "pexRNetwork.h"
#include "gsiEnums.h"
namespace gsi
{
static unsigned int via_get_bottom_conductor (const pex::RExtractorTechVia *via)
{
return via->bottom_conductor;
}
static void via_set_bottom_conductor (pex::RExtractorTechVia *via, unsigned int l)
{
via->bottom_conductor = l;
}
static unsigned int via_get_cut_layer (const pex::RExtractorTechVia *via)
{
return via->cut_layer;
}
static void via_set_cut_layer (pex::RExtractorTechVia *via, unsigned int l)
{
via->cut_layer = l;
}
static unsigned int via_get_top_conductor (const pex::RExtractorTechVia *via)
{
return via->top_conductor;
}
static void via_set_top_conductor (pex::RExtractorTechVia *via, unsigned int l)
{
via->top_conductor = l;
}
static double via_get_resistance (const pex::RExtractorTechVia *via)
{
return via->resistance;
}
static void via_set_resistance (pex::RExtractorTechVia *via, double r)
{
via->resistance = r;
}
static double via_get_merge_distance (const pex::RExtractorTechVia *via)
{
return via->merge_distance;
}
static void via_set_merge_distance (pex::RExtractorTechVia *via, double dist)
{
via->merge_distance = dist;
}
Class<pex::RExtractorTechVia> decl_RExtractorTechVia ("pex", "RExtractorTechVia",
gsi::method_ext ("merge_distance", &via_get_merge_distance,
"@brief Gets the merge distance\n"
"If this value is not zero, it specifies the distance below (or equal) which "
"vias are merged into bigger blocks. This is an optimization to reduce the "
"complexity of the via extraction. The value is given in micrometers."
) +
gsi::method_ext ("merge_distance=", &via_set_merge_distance, gsi::arg ("d"),
"@brief Sets the merge distance\n"
"See \\merge_distance for a description of this attribute."
) +
gsi::method_ext ("resistance", &via_get_resistance,
"@brief Gets the area resistance value of the vias\n"
"This value specifies the via resistance in Ohm * square micrometers. "
"The actual resistance is obtained by dividing this value by the via area."
) +
gsi::method_ext ("resistance=", &via_set_resistance, gsi::arg ("d"),
"@brief Sets the via area resistance value\n"
"See \\resistance for a description of this attribute."
) +
gsi::method_ext ("bottom_conductor", &via_get_bottom_conductor,
"@brief Gets the bottom conductor layer index\n"
"The layer index is a generic identifier for the layer. It is the value used as key in the "
"geometry and port arguments of \\RNetExtractor#extract."
) +
gsi::method_ext ("bottom_conductor=", &via_set_bottom_conductor, gsi::arg ("l"),
"@brief Sets the via bottom conductor layer index\n"
"See \\bottom_conductor for a description of this attribute."
) +
gsi::method_ext ("cut_layer", &via_get_cut_layer,
"@brief Gets the cut layer index\n"
"The layer index is a generic identifier for the layer. It is the value used as key in the "
"geometry and port arguments of \\RNetExtractor#extract. "
"The cut layer is the layer where the via exists."
) +
gsi::method_ext ("cut_layer=", &via_set_cut_layer, gsi::arg ("l"),
"@brief Sets the cut layer index\n"
"See \\cut_layer for a description of this attribute."
) +
gsi::method_ext ("top_conductor", &via_get_top_conductor,
"@brief Gets the top conductor layer index\n"
"The layer index is a generic identifier for the layer. It is the value used as key in the "
"geometry and port arguments of \\RNetExtractor#extract."
) +
gsi::method_ext ("top_conductor=", &via_set_top_conductor, gsi::arg ("l"),
"@brief Sets the via top conductor layer index\n"
"See \\top_conductor for a description of this attribute."
),
"@brief Describes a via for the network extraction.\n"
"This class is used to describe a via type in the context of "
"the \\RExtractorTech#extract method.\n"
"\n"
"This class has been introduced in version 0.30.2."
);
static pex::RExtractorTechConductor::Algorithm cond_get_algorithm (const pex::RExtractorTechConductor *cond)
{
return cond->algorithm;
}
static void cond_set_algorithm (pex::RExtractorTechConductor *cond, pex::RExtractorTechConductor::Algorithm a)
{
cond->algorithm = a;
}
static unsigned int cond_get_layer (const pex::RExtractorTechConductor *cond)
{
return cond->layer;
}
static void cond_set_layer (pex::RExtractorTechConductor *cond, unsigned int l)
{
cond->layer = l;
}
static double cond_get_resistance (const pex::RExtractorTechConductor *cond)
{
return cond->resistance;
}
static void cond_set_resistance (pex::RExtractorTechConductor *cond, double r)
{
cond->resistance = r;
}
static double cond_get_triangulation_min_b (const pex::RExtractorTechConductor *cond)
{
return cond->triangulation_min_b;
}
static void cond_set_triangulation_min_b (pex::RExtractorTechConductor *cond, double min_b)
{
cond->triangulation_min_b = min_b;
}
static double cond_get_triangulation_max_area (const pex::RExtractorTechConductor *cond)
{
return cond->triangulation_max_area;
}
static void cond_set_triangulation_max_area (pex::RExtractorTechConductor *cond, double max_area)
{
cond->triangulation_max_area = max_area;
}
Class<pex::RExtractorTechConductor> decl_RExtractorTechConductor ("pex", "RExtractorTechConductor",
gsi::method_ext ("algorithm", &cond_get_algorithm,
"@brief Gets the algorithm to use\n"
"Specifies the algorithm to use. The default algorithm is 'SquareCounting'."
) +
gsi::method_ext ("algorithm=", &cond_set_algorithm, gsi::arg ("d"),
"@brief Sets the algorithm to use\n"
"See \\algorithm for a description of this attribute."
) +
gsi::method_ext ("resistance", &cond_get_resistance,
"@brief Gets the sheet resistance value of the conductor layer\n"
"This value specifies the cond resistance in Ohm per square. "
"The actual resistance is obtained by multiplying this value with the number of squares."
) +
gsi::method_ext ("resistance=", &cond_set_resistance, gsi::arg ("r"),
"@brief Sets the sheet resistance value of the conductor layer\n"
"See \\resistance for a description of this attribute."
) +
gsi::method_ext ("layer", &cond_get_layer,
"@brief Gets the layer index\n"
"The layer index is a generic identifier for the layer. It is the value used as key in the "
"geometry and port arguments of \\RNetExtractor#extract. "
"This attribute specifies the layer the conductor is on."
) +
gsi::method_ext ("layer=", &cond_set_layer, gsi::arg ("l"),
"@brief Sets the layer index\n"
"See \\layer for a description of this attribute."
) +
gsi::method_ext ("triangulation_min_b", &cond_get_triangulation_min_b,
"@brief Gets the triangulation 'min_b' parameter\n"
"This parameter is used for the 'Tesselation' algorithm and specifies the shortest edge to circle radius ratio of "
"the Delaunay triangulation. "
) +
gsi::method_ext ("triangulation_min_b=", &cond_set_triangulation_min_b, gsi::arg ("min_b"),
"@brief Sets the triangulation 'min_b' parameter\n"
"See \\triangulation_min_b for a description of this attribute."
) +
gsi::method_ext ("triangulation_max_area", &cond_get_triangulation_max_area,
"@brief Gets the triangulation 'max_area' parameter\n"
"This parameter is used for the 'Tesselation' algorithm and specifies the maximum area of "
"the triangles in square micrometers."
) +
gsi::method_ext ("triangulation_max_area=", &cond_set_triangulation_max_area, gsi::arg ("max_area"),
"@brief Sets the triangulation 'max_area' parameter\n"
"See \\triangulation_max_area for a description of this attribute."
),
"@brief Describes a conductor layer for the network extraction.\n"
"This class is used to describe a conductor layer in the context of "
"the \\RExtractorTech#extract method.\n"
"\n"
"This class has been introduced in version 0.30.2."
);
gsi::Enum<pex::RExtractorTechConductor::Algorithm> decl_RExtractorTechConductor_Algorithm ("pex", "Algorithm",
gsi::enum_const ("SquareCounting", pex::RExtractorTechConductor::SquareCounting,
"@brief Specifies the square counting algorithm for \\RExtractorTechConductor#algorithm.\n"
"See \\RExtractor#square_counting_extractor for more details."
) +
gsi::enum_const ("Tesselation", pex::RExtractorTechConductor::Tesselation,
"@brief Specifies the square counting algorithm for \\RExtractorTechConductor#algorithm.\n"
"See \\RExtractor#tesselation_extractor for more details."
),
"@brief This enum represents the extraction algorithm for \\RExtractorTechConductor.\n"
"\n"
"This enum has been introduced in version 0.30.2."
);
gsi::ClassExt<pex::RExtractorTechConductor> inject_RExtractorTechConductor_in_parent (decl_RExtractorTechConductor_Algorithm.defs ());
static bool tech_get_skip_simplify (const pex::RExtractorTech *tech)
{
return tech->skip_simplify;
}
static void tech_set_skip_simplify (pex::RExtractorTech *tech, bool f)
{
tech->skip_simplify = f;
}
static auto tech_begin_vias (const pex::RExtractorTech *tech)
{
return tech->vias.begin ();
}
static auto tech_end_vias (const pex::RExtractorTech *tech)
{
return tech->vias.end ();
}
static void tech_clear_vias (pex::RExtractorTech *tech)
{
tech->vias.clear ();
}
static void tech_add_via (pex::RExtractorTech *tech, const pex::RExtractorTechVia &via)
{
tech->vias.push_back (via);
}
static auto tech_begin_conductors (const pex::RExtractorTech *tech)
{
return tech->conductors.begin ();
}
static auto tech_end_conductors (const pex::RExtractorTech *tech)
{
return tech->conductors.end ();
}
static void tech_clear_conductors (pex::RExtractorTech *tech)
{
tech->conductors.clear ();
}
static void tech_add_conductor (pex::RExtractorTech *tech, const pex::RExtractorTechConductor &conductor)
{
tech->conductors.push_back (conductor);
}
Class<pex::RExtractorTech> decl_RExtractorTech ("pex", "RExtractorTech",
gsi::method_ext ("skip_simplify", &tech_get_skip_simplify,
"@brief Gets a value indicating whether to skip the simplify step\n"
"This values specifies to skip the simplify step of the network after the extraction has "
"been done. By default, the network is simplified - i.e. serial resistors are joined etc. "
"By setting this attribute to 'false', this step is skipped."
) +
gsi::method_ext ("skip_simplify=", &tech_set_skip_simplify, gsi::arg ("f"),
"@brief Sets a value indicating whether to skip the simplify step\n"
"See \\skip_simplify for a description of this attribute."
) +
gsi::method_ext ("each_via", &tech_begin_vias, &tech_end_vias,
"@brief Iterates the list of via definitions\n"
) +
gsi::method_ext ("clear_vias", &tech_clear_vias,
"@brief Clears the list of via definitions\n"
) +
gsi::method_ext ("add_via", &tech_add_via, gsi::arg ("via"),
"@brief Adds the given via definition to the list of vias\n"
) +
gsi::method_ext ("each_conductor", &tech_begin_conductors, &tech_end_conductors,
"@brief Iterates the list of conductor definitions\n"
) +
gsi::method_ext ("clear_conductors", &tech_clear_conductors,
"@brief Clears the list of conductor definitions\n"
) +
gsi::method_ext ("add_conductor", &tech_add_conductor, gsi::arg ("conductor"),
"@brief Adds the given conductor definition to the list of conductors\n"
),
"@brief Specifies the tech stack for the R extraction.\n"
"The tech stack is a collection of via and conductor definitions and some other attributes. "
"It is used for the \\RNetExtractor#extract method.\n"
"\n"
"This enum has been introduced in version 0.30.2."
);
static pex::RNetExtractor *new_net_rextractor (double dbu)
{
return new pex::RNetExtractor (dbu);
}
static pex::RNetwork *rex_extract (pex::RNetExtractor *rex,
const pex::RExtractorTech *tech,
const std::map<unsigned int, db::Region> *geo,
const std::map<unsigned int, std::vector<db::Point> > *vertex_ports,
const std::map<unsigned int, std::vector<db::Polygon> > *polygon_ports)
{
std::unique_ptr<pex::RNetwork> network (new pex::RNetwork ());
std::map<unsigned int, db::Region> empty_geo;
std::map<unsigned int, std::vector<db::Point> > empty_vertex_ports;
std::map<unsigned int, std::vector<db::Polygon> > empty_polygon_ports;
rex->extract (*tech, geo ? *geo : empty_geo, vertex_ports ? *vertex_ports : empty_vertex_ports, polygon_ports ? *polygon_ports : empty_polygon_ports, *network);
return network.release ();
}
Class<pex::RNetExtractor> decl_RNetExtractor ("pex", "RNetExtractor",
gsi::constructor ("new", &new_net_rextractor, gsi::arg ("dbu"),
"@brief Creates a network R extractor\n"
"\n"
"@param dbu The database unit of the polygons the extractor will work on\n"
"@param skip_simplify If true, the final step to simplify the netlist will be skipped. This feature is for testing mainly.\n"
"@return A new \\RNetExtractor object that implements the net extractor\n"
) +
gsi::factory_ext ("extract", &rex_extract, gsi::arg ("tech_stack"), gsi::arg ("geo"), gsi::arg ("vertex_ports"), gsi::arg ("polygon_ports"),
"@brief Runs the extraction on the given multi-layer geometry\n"
"See the description of the class for more details."
),
"@brief The network R extractor class\n"
"\n"
"This class provides the algorithms for extracting a R network from a multi-layer arrangement of conductors and vias.\n"
"The main feature is the \\extract method. It takes a multi-layer geometry, a tech stack and a number of port definitions\n"
"and returns a R network. The nodes in that network are annotated, so the corresponding port can be deduced from a node of\n"
"VertexPort or PolygonPort type.\n"
"\n"
"Layers are given by layer indexes - those are generic IDs. Every layer has to be given a unique ID, which must be used throughout "
"the different specifications (geometry, vias, conductors, ports).\n"
"\n"
"Two kind of ports are provided: point-like vertex ports and polygon ports. Polygons for polygon ports should be convex and sit inside "
"the geometry they mark. Ports become nodes in the network. Beside ports, the network can have internal nodes. Nodes are annotated with "
"a type (vertex, polygon, internal) and an index and layer. The layer is the layer ID, the index specifies the position of the "
"corresponding port in the 'vertex_ports' or 'polygon_ports' list of the \\extract call.\n"
"\n"
"This class has been introduced in version 0.30.2\n"
);
}

View File

@ -0,0 +1,412 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2025 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "gsiDecl.h"
#include "pexRExtractor.h"
#include "pexSquareCountingRExtractor.h"
#include "pexTriangulationRExtractor.h"
#include "gsiEnums.h"
namespace gsi
{
class RNode
{
public:
~RNode () { }
pex::RNode::node_type type () const { return checked_pointer ()->type; }
db::DBox location () const { return checked_pointer ()->location; }
unsigned int port_index () const { return checked_pointer ()->port_index; }
unsigned int layer () const { return checked_pointer ()->layer; }
std::string to_string (bool with_coords = false) const { return checked_pointer ()->to_string (with_coords); }
size_t obj_id () const
{
return size_t (mp_ptr);
}
static RNode *make_node_object (const pex::RNode *node)
{
return new RNode (node);
}
const pex::RNode *checked_pointer () const
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RNode object no longer is valid")));
}
return mp_ptr;
}
pex::RNode *checked_pointer ()
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RNode object no longer is valid")));
}
return const_cast<pex::RNode *> (mp_ptr);
}
private:
tl::weak_ptr<pex::RNetwork> mp_graph;
const pex::RNode *mp_ptr;
RNode (const pex::RNode *node)
: mp_graph (node->graph ()),
mp_ptr (node)
{
// .. nothing yet ..
}
};
class RElement
{
public:
~RElement () { }
double conductance () const { return checked_pointer ()->conductance; }
double resistance () const { return checked_pointer ()->resistance (); }
RNode *a () const { return RNode::make_node_object (checked_pointer ()->a ()); }
RNode *b () const { return RNode::make_node_object (checked_pointer ()->b ()); }
std::string to_string (bool with_coords = false) const { return checked_pointer ()->to_string (with_coords); }
size_t obj_id () const
{
return size_t (mp_ptr);
}
static RElement *make_element_object (const pex::RElement *element)
{
return new RElement (element);
}
const pex::RElement *checked_pointer () const
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RElement object no longer is valid")));
}
return mp_ptr;
}
pex::RElement *checked_pointer ()
{
if (! mp_graph.get ()) {
throw tl::Exception (tl::to_string (tr ("Network graph has been destroyed - RElement object no longer is valid")));
}
return const_cast<pex::RElement *> (mp_ptr);
}
private:
tl::weak_ptr<pex::RNetwork> mp_graph;
const pex::RElement *mp_ptr;
RElement (const pex::RElement *node)
: mp_graph (node->graph ()),
mp_ptr (node)
{
// .. nothing yet ..
}
};
class RElementIterator
{
public:
typedef std::list<const pex::RElement *>::const_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RElement *value_type;
typedef RElement *reference;
typedef void pointer;
typedef void difference_type;
RElementIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const RElementIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RElement *operator* () const
{
return RElement::make_element_object (*m_it);
}
private:
basic_iter m_it;
};
static RElementIterator begin_node_elements (RNode *node)
{
return RElementIterator (node->checked_pointer ()->elements ().begin ());
}
static RElementIterator end_network_elements (RNode *node)
{
return RElementIterator (node->checked_pointer ()->elements ().end ());
}
gsi::Enum<pex::RNode::node_type> decl_NodeType ("pex", "RNodeType",
gsi::enum_const ("Internal", pex::RNode::Internal,
"@brief Specifies an internal node in a R network\n"
"Internal nodes are generated during the R extraction process. "
"The port index of such a node is an arbitrary index."
) +
gsi::enum_const ("VertexPort", pex::RNode::VertexPort,
"@brief Specifies a vertex port node in a R network\n"
"Vertex port nodes are generated for vertex ports in \\RExtractor#extract, see 'vertex_ports' argument. "
"The port index of such a node refers to the position in that list."
) +
gsi::enum_const ("PolygonPort", pex::RNode::PolygonPort,
"@brief Specifies a polygon port node in a R network\n"
"Polygon port nodes are generated for polygon ports in \\RExtractor#extract, see 'polygon_ports' argument. "
"The port index of such a node refers to the position in that list."
),
"@brief This class represents the node type for RNode.\n"
"\n"
"This class has been introduced in version 0.30.2"
);
Class<RNode> decl_RNode ("pex", "RNode",
gsi::method ("object_id", &RNode::obj_id,
"@brief Returns an ID representing the actual object\n"
"For every call, a new instance of this object is created, while multiple "
"ones may represent the same internal object. The 'object_id' is a ID that "
"indicates the internal object. Same object_id means same node."
) +
gsi::method ("to_s", &RNode::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of this object\n"
"Nodes are printed with coordinates with 'with_coords' is true."
) +
gsi::iterator_ext ("each_element", gsi::return_new_object (), &begin_node_elements, &end_network_elements,
"@brief Iterates the \\RElement objects attached to the node\n"
) +
gsi::method ("type", &RNode::type,
"@brief Gets the type attribute of the node\n"
) +
gsi::method ("location", &RNode::location,
"@brief Gets the location attribute of the node\n"
"The location defined the original position of the node"
) +
gsi::method ("port_index", &RNode::port_index,
"@brief Gets the port index of the node\n"
"The port index associates a node with a original port definition."
) +
gsi::method ("layer", &RNode::layer,
"@brief Gets the Layer ID of the node\n"
"The port index associates a node with a original port definition layer-wise."
),
"@brief Represents a node in a R network graph\n"
"See \\RNetwork for a description of this object\n"
"\n"
"This class has been introduced in version 0.30.2"
);
// Inject the RNode::node_type declarations into RNode
gsi::ClassExt<RNode> inject_NodeType_in_RNode (decl_NodeType.defs ());
Class<RElement> decl_RElement ("pex", "RElement",
gsi::method ("object_id", &RElement::obj_id,
"@brief Returns an ID representing the actual object\n"
"For every call, a new instance of this object is created, while multiple "
"ones may represent the same internal object. The 'object_id' is a ID that "
"indicates the internal object. Same object_id means same element."
) +
gsi::method ("to_s", &RElement::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of this object\n"
"Nodes are printed with coordinates with 'with_coords' is true."
) +
gsi::method ("resistance", &RElement::resistance,
"@brief Gets the resistance value of the object\n"
) +
gsi::factory ("a", &RElement::a,
"@brief Gets the first node the element connects\n"
) +
gsi::factory ("b", &RElement::b,
"@brief Gets the second node the element connects\n"
),
"@brief Represents an edge (also called element) in a R network graph\n"
"See \\RNetwork for a description of this object"
"\n"
"This class has been introduced in version 0.30.2"
);
static RNode *create_node (pex::RNetwork *network, pex::RNode::node_type type, unsigned int port_index, unsigned int layer)
{
return RNode::make_node_object (network->create_node (type, port_index, layer));
}
static RElement *create_element (pex::RNetwork *network, double r, RNode *a, RNode *b)
{
double s = fabs (r) < 1e-10 ? pex::RElement::short_value () : 1.0 / r;
return RElement::make_element_object (network->create_element (s, a->checked_pointer (), b->checked_pointer ()));
}
static void remove_element (pex::RNetwork *network, RElement *element)
{
network->remove_element (element->checked_pointer ());
}
static void remove_node (pex::RNetwork *network, RNode *node)
{
network->remove_node (node->checked_pointer ());
}
class NetworkElementIterator
{
public:
typedef pex::RNetwork::element_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RElement *value_type;
typedef RElement *reference;
typedef void pointer;
typedef void difference_type;
NetworkElementIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const NetworkElementIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RElement *operator* () const
{
return RElement::make_element_object (m_it.operator-> ());
}
private:
basic_iter m_it;
};
static NetworkElementIterator begin_network_elements (pex::RNetwork *network)
{
return NetworkElementIterator (network->begin_elements ());
}
static NetworkElementIterator end_network_elements (pex::RNetwork *network)
{
return NetworkElementIterator (network->end_elements ());
}
class NetworkNodeIterator
{
public:
typedef pex::RNetwork::node_iterator basic_iter;
typedef std::forward_iterator_tag iterator_category;
typedef RNode *value_type;
typedef RNode *reference;
typedef void pointer;
typedef void difference_type;
NetworkNodeIterator (basic_iter it)
: m_it (it)
{ }
bool operator== (const NetworkNodeIterator &it) const { return m_it == it.m_it; }
void operator++ () { ++m_it; }
RNode *operator* () const
{
return RNode::make_node_object (m_it.operator-> ());
}
private:
basic_iter m_it;
};
static NetworkNodeIterator begin_network_nodes (pex::RNetwork *network)
{
return NetworkNodeIterator (network->begin_nodes ());
}
static NetworkNodeIterator end_network_nodes (pex::RNetwork *network)
{
return NetworkNodeIterator (network->end_nodes ());
}
Class<pex::RNetwork> decl_RNetwork ("pex", "RNetwork",
gsi::factory_ext ("create_node", &create_node, gsi::arg ("type"), gsi::arg ("port_index"), gsi::arg ("layer", (unsigned int) 0),
"@brief Creates a new node with the given type and index'.\n"
"@return A reference to the new nbode object."
) +
gsi::factory_ext ("create_element", &create_element, gsi::arg ("resistance"), gsi::arg ("a"), gsi::arg ("b"),
"@brief Creates a new element between the nodes given by 'a' abd 'b'.\n"
"If a resistor already exists between the two nodes, both resistors are combined into one.\n"
"@return A reference to the new resistor object."
) +
gsi::method_ext ("remove_element", &remove_element, gsi::arg ("element"),
"@brief Removes the given element\n"
"If removing the element renders an internal node orphan (i.e. without elements), this "
"node is removed too."
) +
gsi::method_ext ("remove_node", &remove_node, gsi::arg ("node"),
"@brief Removes the given node\n"
"Only internal nodes can be removed. Removing a node will also remove the "
"elements attached to this node."
) +
gsi::method ("clear", &pex::RNetwork::clear,
"@brief Clears the network\n"
) +
gsi::method ("simplify", &pex::RNetwork::simplify,
"@brief Simplifies the network\n"
"\n"
"This will:\n"
"@ul\n"
"@li Join serial resistors if connected by an internal node @/li\n"
"@li Remove shorts and join the nodes, if one of them is\n"
" an internal node. The non-internal node will persist @/li\n"
"@li Remove \"dangling\" resistors if the dangling node is\n"
" an internal one @/li\n"
"@/ul\n"
) +
gsi::iterator_ext ("each_element", gsi::return_new_object (), &begin_network_elements, &end_network_elements,
"@brief Iterates the \\RElement objects inside the network\n"
) +
gsi::iterator_ext ("each_node", gsi::return_new_object (), &begin_network_nodes, &end_network_nodes,
"@brief Iterates the \\RNode objects inside the network\n"
) +
gsi::method ("num_nodes", &pex::RNetwork::num_nodes,
"@brief Gets the total number of nodes in the network\n"
) +
gsi::method ("num_internal_nodes", &pex::RNetwork::num_internal_nodes,
"@brief Gets the number of internal nodes in the network\n"
) +
gsi::method ("num_elements", &pex::RNetwork::num_elements,
"@brief Gets the number of elements in the network\n"
) +
gsi::method ("to_s", &pex::RNetwork::to_string, gsi::arg ("with_coords", false),
"@brief Returns a string representation of the network\n"
"Nodes are printed with coordinates with 'with_coords' is true."
),
"@brief Represents a network of resistors\n"
"\n"
"The network is basically a graph with nodes and edges (the resistors). "
"The resistors are called 'elements' and are represented by \\RElement objects. "
"The nodes are represented by \\RNode objects. "
"The network is created by \\RExtractor#extract, which turns a polygon into a resistor network.\n"
"\n"
"This class has been introduced in version 0.30.2\n"
);
}

View File

@ -7,6 +7,8 @@ include($$PWD/../../lib.pri)
DEFINES += MAKE_PEX_LIBRARY
SOURCES = \
gsiDeclRNetExtractor.cc \
gsiDeclRNetwork.cc \
pexForceLink.cc \
pexRExtractor.cc \
gsiDeclRExtractor.cc \

View File

@ -97,10 +97,10 @@ public:
SquareCounting = 0,
/**
* @brief The triangulation algorithm
* @brief The tesselation algorithm
* This algorithm is suitable to "large" sheets, specifically substrate.
*/
Triangulation = 1
Tesselation = 1
};
/**

View File

@ -69,19 +69,6 @@ RNetExtractor::extract (const RExtractorTech &tech,
continue;
}
// Compute the offsets for the port indexes
// The port indexes are assigned incrementally, so the first index of a port
// for layer n is:
// size(ports for layer 0) + ... + size(ports for layer n-1)
// (size is 0 for empty port list)
unsigned int vp_offset = 0, pp_offset = 0;
for (auto p = vertex_ports.begin (); p != vertex_ports.end () && p->first < g->first; ++p) {
vp_offset += p->second.size ();
}
for (auto p = polygon_ports.begin (); p != polygon_ports.end () && p->first < g->first; ++p) {
pp_offset += p->second.size ();
}
// fetch the port list for vertex ports
auto ivp = vertex_ports.find (g->first);
static std::vector<db::Point> empty_vertex_ports;
@ -98,7 +85,7 @@ RNetExtractor::extract (const RExtractorTech &tech,
const std::vector<ViaPort> &viap = iviap == via_ports.end () ? empty_via_ports : iviap->second;
// extract the conductor polygon and integrate the results into the target network
extract_conductor (*cond, g->second, vp, vp_offset, pp, pp_offset, viap, rnetwork);
extract_conductor (*cond, g->second, vp, pp, viap, rnetwork);
}
@ -178,8 +165,8 @@ RNetExtractor::create_via_port (const pex::RExtractorTechVia &tech,
std::map<unsigned int, std::vector<ViaPort> > &vias,
RNetwork &rnetwork)
{
RNode *a = rnetwork.create_node (RNode::Internal, port_index++);
RNode *b = rnetwork.create_node (RNode::Internal, port_index++);
RNode *a = rnetwork.create_node (RNode::Internal, port_index++, tech.bottom_conductor);
RNode *b = rnetwork.create_node (RNode::Internal, port_index++, tech.top_conductor);
db::CplxTrans to_um (m_dbu);
db::Box box = poly.box ();
@ -266,9 +253,7 @@ class ExtractingReceiver
public:
ExtractingReceiver (const RExtractorTechConductor *cond,
const std::vector<db::Point> *vertex_ports,
unsigned int vertex_port_index_offset,
const std::vector<db::Polygon> *polygon_ports,
unsigned int polygon_port_index_offset,
const std::vector<RNetExtractor::ViaPort> *via_ports,
double dbu,
RNetwork *rnetwork)
@ -277,8 +262,6 @@ public:
mp_polygon_ports (polygon_ports),
mp_via_ports (via_ports),
m_next_internal_port_index (0),
m_vertex_port_index_offset (vertex_port_index_offset),
m_polygon_port_index_offset (polygon_port_index_offset),
m_dbu (dbu),
mp_rnetwork (rnetwork)
{
@ -316,8 +299,6 @@ private:
const std::vector<RNetExtractor::ViaPort> *mp_via_ports;
std::map<size_t, RNode *> m_id_to_node;
unsigned int m_next_internal_port_index;
unsigned int m_vertex_port_index_offset;
unsigned int m_polygon_port_index_offset;
double m_dbu;
RNetwork *mp_rnetwork;
@ -355,7 +336,7 @@ private:
rex.extract (poly, local_vertex_ports, local_polygon_ports, local_network);
}
break;
case RExtractorTechConductor::Triangulation:
case RExtractorTechConductor::Tesselation:
{
pex::TriangulationRExtractor rex (m_dbu);
rex.extract (poly, local_vertex_ports, local_polygon_ports, local_network);
@ -380,7 +361,7 @@ private:
if (local->type == RNode::Internal) {
// for internal nodes always create a node in the target network
global = mp_rnetwork->create_node (local->type, ++m_next_internal_port_index);
global = mp_rnetwork->create_node (local->type, ++m_next_internal_port_index, mp_cond->layer);
global->location = local->location;
} else if (local->type == RNode::VertexPort) {
@ -395,7 +376,7 @@ private:
global = i2n->second;
} else {
if (type_from_id (id) == 0) { // vertex port
global = mp_rnetwork->create_node (RNode::VertexPort, index_from_id (id) + m_vertex_port_index_offset);
global = mp_rnetwork->create_node (RNode::VertexPort, index_from_id (id), mp_cond->layer);
global->location = local->location;
} else if (type_from_id (id) == 1) { // via port
global = (*mp_via_ports) [index_from_id (id)].node;
@ -414,7 +395,7 @@ private:
if (i2n != m_id_to_node.end ()) {
global = i2n->second;
} else {
global = mp_rnetwork->create_node (RNode::PolygonPort, index_from_id (id) + m_polygon_port_index_offset);
global = mp_rnetwork->create_node (RNode::PolygonPort, index_from_id (id), mp_cond->layer);
global->location = local->location;
m_id_to_node.insert (std::make_pair (id, global));
}
@ -455,9 +436,7 @@ void
RNetExtractor::extract_conductor (const RExtractorTechConductor &cond,
const db::Region &region,
const std::vector<db::Point> &vertex_ports,
unsigned int vertex_ports_index_offset,
const std::vector<db::Polygon> &polygon_ports,
unsigned int polygon_ports_index_offset,
const std::vector<ViaPort> &via_ports,
RNetwork &rnetwork)
{
@ -490,7 +469,7 @@ RNetExtractor::extract_conductor (const RExtractorTechConductor &cond,
scanner.insert2 (&box_heap.back (), make_id (i - polygon_ports.begin (), 2));
}
ExtractingReceiver rec (&cond, &vertex_ports, vertex_ports_index_offset, &polygon_ports, polygon_ports_index_offset, &via_ports, m_dbu, &rnetwork);
ExtractingReceiver rec (&cond, &vertex_ports, &polygon_ports, &via_ports, m_dbu, &rnetwork);
scanner.process (rec, 0, db::box_convert<db::Polygon> (), db::box_convert<db::Box> ());
}

View File

@ -84,9 +84,7 @@ protected:
void extract_conductor (const RExtractorTechConductor &cond,
const db::Region &region,
const std::vector<db::Point> &vertex_ports,
unsigned int vertex_ports_index_offset,
const std::vector<db::Polygon> &polygon_ports,
unsigned int polygon_ports_index_offset,
const std::vector<ViaPort> &via_ports,
RNetwork &rnetwork);

View File

@ -33,19 +33,24 @@ std::string
RNode::to_string (bool with_coords) const
{
std::string res;
switch (type) {
default:
res += "$" + tl::to_string (port_index);
res += "$";
break;
case VertexPort:
res += "V" + tl::to_string (port_index);
res += "V";
break;
case PolygonPort:
res += "P" + tl::to_string (port_index);
res += "P";
break;
}
res += tl::to_string (port_index);
if (layer > 0) {
res += ".";
res += tl::to_string (layer);
}
if (with_coords) {
res += location.to_string ();
}
@ -116,27 +121,27 @@ RNetwork::clear ()
}
RNode *
RNetwork::create_node (RNode::node_type type, unsigned int port_index)
RNetwork::create_node (RNode::node_type type, unsigned int port_index, unsigned int layer)
{
if (type != RNode::Internal) {
auto i = m_nodes_by_type.find (std::make_pair (type, port_index));
auto i = m_nodes_by_type.find (std::make_pair (type, std::make_pair (port_index, layer)));
if (i != m_nodes_by_type.end ()) {
return i->second;
} else {
RNode *new_node = new RNode (this, type, db::DBox (), port_index);
RNode *new_node = new RNode (this, type, db::DBox (), port_index, layer);
m_nodes.push_back (new_node);
m_nodes_by_type.insert (std::make_pair (std::make_pair (type, port_index), new_node));
m_nodes_by_type.insert (std::make_pair (std::make_pair (type, std::make_pair (port_index, layer)), new_node));
return new_node;
}
} else {
RNode *new_node = new RNode (this, type, db::DBox (), port_index);
RNode *new_node = new RNode (this, type, db::DBox (), port_index, layer);
m_nodes.push_back (new_node);
return new_node;

View File

@ -80,6 +80,13 @@ public:
*/
unsigned int port_index;
/**
* @brief An index locating the node in a layer
*
* For internal nodes, the layer is 0.
*/
unsigned int layer;
/**
* @brief Gets the R elements connected to this node
*/
@ -106,8 +113,8 @@ protected:
friend class RElement;
friend class tl::list_impl<RNode, false>;
RNode (RNetwork *network, node_type _type, const db::DBox &_location, unsigned int _port_index)
: type (_type), location (_location), port_index (_port_index), mp_network (network)
RNode (RNetwork *network, node_type _type, const db::DBox &_location, unsigned int _port_index, unsigned int _layer)
: type (_type), location (_location), port_index (_port_index), layer (_layer), mp_network (network)
{ }
~RNode () { }
@ -249,7 +256,7 @@ public:
* or port index already. This avoids creating duplicates
* for the same port.
*/
RNode *create_node (RNode::node_type type, unsigned int port_index);
RNode *create_node (RNode::node_type type, unsigned int port_index, unsigned int layer);
/**
* @brief Creates a new element between the given nodes
@ -363,7 +370,7 @@ private:
node_list m_nodes;
element_list m_elements;
std::map<std::pair<RNode *, RNode *>, RElement *> m_elements_by_nodes;
std::map<std::pair<RNode::node_type, unsigned int>, RNode *> m_nodes_by_type;
std::map<std::pair<RNode::node_type, std::pair<unsigned int, unsigned int> >, RNode *> m_nodes_by_type;
RNetwork (const RNetwork &);
RNetwork &operator= (const RNetwork &);

View File

@ -287,7 +287,7 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
for (auto p = ports.begin (); p != ports.end (); ++p) {
auto n4p = nodes_for_ports.find (p->first);
if (n4p == nodes_for_ports.end ()) {
pex::RNode *node = rnetwork.create_node (p->first.type, p->first.port_index);
pex::RNode *node = rnetwork.create_node (p->first.type, p->first.port_index, 0);
node->location = to_um * p->first.location;
n4p = nodes_for_ports.insert (std::make_pair (p->first, node)).first;
}

View File

@ -148,7 +148,7 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
if (pn != pport_nodes.end ()) {
n = pn->second;
} else {
n = rnetwork.create_node (pex::RNode::PolygonPort, port_index);
n = rnetwork.create_node (pex::RNode::PolygonPort, port_index, 0);
pport_nodes.insert (std::make_pair (port_index, n));
n->location = trans * polygon_ports [port_index].box ();
}
@ -158,7 +158,7 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
for (auto pi = vertex->ids ().begin (); pi != vertex->ids ().end (); ++pi) {
size_t port_index = size_t (*pi);
if (port_index < vertex_ports.size ()) {
RNode *nn = rnetwork.create_node (pex::RNode::VertexPort, port_index);
RNode *nn = rnetwork.create_node (pex::RNode::VertexPort, port_index, 0);
nn->location = db::DBox (*vertex, *vertex);
if (n) {
// in case of multiple vertexes on the same spot, short them
@ -172,7 +172,7 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
} else {
n = rnetwork.create_node (pex::RNode::Internal, internal_node_id++);
n = rnetwork.create_node (pex::RNode::Internal, internal_node_id++, 0);
n->location = db::DBox (*vertex, *vertex);
}
@ -204,7 +204,7 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
if (ip != pport_nodes.end ()) {
// create a new vertex port and short it to the polygon port
auto n = rnetwork.create_node (pex::RNode::VertexPort, iv);
auto n = rnetwork.create_node (pex::RNode::VertexPort, iv, 0);
n->location = db::DBox (trans * vp, trans * vp);
rnetwork.create_element (pex::RElement::short_value (), n, ip->second);

View File

@ -30,15 +30,74 @@ TEST(network_basic)
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::Internal, 1);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2);
pex::RNode *n1 = rn.create_node (pex::RNode::Internal, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 1, 1);
EXPECT_EQ (n1 != n2, true);
pex::RNode *n2_dup = rn.create_node (pex::RNode::Internal, 1, 1);
EXPECT_EQ (n2 != n2_dup, true);
/* pex::RElement *e12 = */ rn.create_element (0.5, n1, n2);
EXPECT_EQ (rn.to_string (),
"R $1 $1.1 2"
);
}
TEST(network_basic_vertex_nodes)
{
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::VertexPort, 1, 1);
EXPECT_EQ (n1 != n2, true);
pex::RNode *n2_dup = rn.create_node (pex::RNode::VertexPort, 1, 1);
EXPECT_EQ (n2 == n2_dup, true);
pex::RNode *n2_wrong_type = rn.create_node (pex::RNode::PolygonPort, 1, 1);
EXPECT_EQ (n2 != n2_wrong_type, true);
/* pex::RElement *e12 = */ rn.create_element (0.5, n1, n2);
EXPECT_EQ (rn.to_string (),
"R V1 V1.1 2"
);
}
TEST(network_basic_polygon_nodes)
{
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::PolygonPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::PolygonPort, 1, 1);
EXPECT_EQ (n1 != n2, true);
pex::RNode *n2_dup = rn.create_node (pex::RNode::PolygonPort, 1, 1);
EXPECT_EQ (n2 == n2_dup, true);
pex::RNode *n2_wrong_type = rn.create_node (pex::RNode::VertexPort, 1, 1);
EXPECT_EQ (n2 != n2_wrong_type, true);
/* pex::RElement *e12 = */ rn.create_element (0.5, n1, n2);
EXPECT_EQ (rn.to_string (),
"R P1 P1.1 2"
);
}
TEST(network_basic_elements)
{
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::Internal, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2, 0);
/* pex::RElement *e12 = */ rn.create_element (0.5, n1, n2);
EXPECT_EQ (rn.to_string (),
"R $1 $2 2"
);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3, 0);
/* pex::RElement *e13 = */ rn.create_element (0.25, n1, n3);
pex::RElement *e23 = rn.create_element (1.0, n2, n3);
@ -89,9 +148,9 @@ TEST(network_simplify1)
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2);
pex::RNode *n3 = rn.create_node (pex::RNode::VertexPort, 3);
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2, 0);
pex::RNode *n3 = rn.create_node (pex::RNode::VertexPort, 3, 0);
rn.create_element (1, n1, n2);
rn.create_element (pex::RElement::short_value (), n2, n3);
@ -115,11 +174,11 @@ TEST(network_simplify2)
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4);
pex::RNode *n5 = rn.create_node (pex::RNode::VertexPort, 5);
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2, 0);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3, 0);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4, 0);
pex::RNode *n5 = rn.create_node (pex::RNode::VertexPort, 5, 0);
rn.create_element (1, n1, n2);
rn.create_element (pex::RElement::short_value (), n2, n3);
@ -147,10 +206,10 @@ TEST(network_simplify3)
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4);
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2, 0);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3, 0);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4, 0);
rn.create_element (1, n1, n2);
rn.create_element (pex::RElement::short_value (), n2, n3);
@ -174,10 +233,10 @@ TEST(network_simplify4)
pex::RNetwork rn;
EXPECT_EQ (rn.to_string (), "");
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4);
pex::RNode *n1 = rn.create_node (pex::RNode::VertexPort, 1, 0);
pex::RNode *n2 = rn.create_node (pex::RNode::Internal, 2, 0);
pex::RNode *n3 = rn.create_node (pex::RNode::Internal, 3, 0);
pex::RNode *n4 = rn.create_node (pex::RNode::VertexPort, 4, 0);
rn.create_element (1, n1, n4);
rn.create_element (1, n2, n1);

View File

@ -79,10 +79,10 @@ TEST(netex_viagen1)
EXPECT_EQ (via_ports [l3].size (), size_t (4));
EXPECT_EQ (network.to_string (true),
"R $0(1.7,0.1;1.9,0.3) $1(1.7,0.1;1.9,0.3) 50\n"
"R $2(0.4,0.5;0.6,0.7) $3(0.4,0.5;0.6,0.7) 50\n"
"R $4(0.8,0.5;1,0.7) $5(0.8,0.5;1,0.7) 50\n"
"R $6(2.9,0.5;3.1,0.7) $7(2.9,0.5;3.1,0.7) 50"
"R $0.1(1.7,0.1;1.9,0.3) $1.2(1.7,0.1;1.9,0.3) 50\n"
"R $2.1(0.4,0.5;0.6,0.7) $3.2(0.4,0.5;0.6,0.7) 50\n"
"R $4.1(0.8,0.5;1,0.7) $5.2(0.8,0.5;1,0.7) 50\n"
"R $6.1(2.9,0.5;3.1,0.7) $7.2(2.9,0.5;3.1,0.7) 50"
);
}
@ -129,12 +129,12 @@ TEST(netex_viagen2)
EXPECT_EQ (via_ports [l3].size (), size_t (6));
EXPECT_EQ (network.to_string (true),
"R $0(4.6,2.8;4.8,3) $1(4.6,2.8;4.8,3) 50\n"
"R $2(2.5,3.7;2.7,3.9) $3(2.5,3.7;2.7,3.9) 50\n"
"R $4(3,3.7;3.2,3.9) $5(3,3.7;3.2,3.9) 50\n"
"R $6(2.2,1.2;3.4,3.4) $7(2.2,1.2;3.4,3.4) 2.77778\n"
"R $8(0.4,0.4;2.2,4.2) $9(0.4,0.4;2.2,4.2) 1\n"
"R $10(0.6,4.9;1.2,5.1) $11(0.6,4.9;1.2,5.1) 25"
"R $0.1(4.6,2.8;4.8,3) $1.2(4.6,2.8;4.8,3) 50\n"
"R $2.1(2.5,3.7;2.7,3.9) $3.2(2.5,3.7;2.7,3.9) 50\n"
"R $4.1(3,3.7;3.2,3.9) $5.2(3,3.7;3.2,3.9) 50\n"
"R $6.1(2.2,1.2;3.4,3.4) $7.2(2.2,1.2;3.4,3.4) 2.77778\n"
"R $8.1(0.4,0.4;2.2,4.2) $9.2(0.4,0.4;2.2,4.2) 1\n"
"R $10.1(0.6,4.9;1.2,5.1) $11.2(0.6,4.9;1.2,5.1) 25"
);
}
@ -162,6 +162,11 @@ TEST(netex_2layer)
unsigned int l3p = ly.get_layer (db::LayerProperties (3, 1));
unsigned int l3v = ly.get_layer (db::LayerProperties (3, 2));
// That is coincidence, but it needs to be that way for the strings to match
EXPECT_EQ (l1, 1u);
EXPECT_EQ (l2, 0u);
EXPECT_EQ (l3, 2u);
std::map<unsigned int, db::Region> geo;
geo.insert (std::make_pair (l1, db::Region (db::RecursiveShapeIterator (ly, ly.cell (tc.second), l1))));
geo.insert (std::make_pair (l2, db::Region (db::RecursiveShapeIterator (ly, ly.cell (tc.second), l2))));
@ -216,19 +221,19 @@ TEST(netex_2layer)
rex.extract (tech, geo, vertex_ports, polygon_ports, network);
EXPECT_EQ (network.to_string (true),
"R $0(0.3,-5.7;0.5,-5.5) $1(0.3,-5.7;0.5,-5.5) 50\n"
"R $2(9.3,-5.9;9.9,-5.3) $3(9.3,-5.9;9.9,-5.3) 12.5\n"
"R $4(9.3,0.1;9.9,0.3) $5(9.3,0.1;9.9,0.3) 25\n"
"R $6(0.1,0.1;0.7,0.7) $7(0.1,0.1;0.7,0.7) 12.5\n"
"R $0(0.3,-5.7;0.5,-5.5) $2(9.3,-5.9;9.9,-5.3) 5.75\n"
"R $2(9.3,-5.9;9.9,-5.3) P0(12.9,-5.9;13.5,-5.3) 2.25\n"
"R $6(0.1,0.1;0.7,0.7) V0(5.2,0.4;5.2,0.4) 3\n"
"R $4(9.3,0.1;9.9,0.3) V0(5.2,0.4;5.2,0.4) 2.75\n"
"R $5(9.3,0.1;9.9,0.3) $8(10,-3.5;10,-2.7) 1.03125\n"
"R $3(9.3,-5.9;9.9,-5.3) $8(10,-3.5;10,-2.7) 0.78125\n"
"R $8(10,-3.5;10,-2.7) P1(12.9,-3.4;13.5,-2.8) 1\n"
"R $7(0.1,0.1;0.7,0.7) V1(0.4,-5.6;0.4,-5.6) 1.875\n"
"R $1(0.3,-5.7;0.5,-5.5) V1(0.4,-5.6;0.4,-5.6) 0"
"R $0.1(0.3,-5.7;0.5,-5.5) $1.2(0.3,-5.7;0.5,-5.5) 50\n"
"R $2.1(9.3,-5.9;9.9,-5.3) $3.2(9.3,-5.9;9.9,-5.3) 12.5\n"
"R $4.1(9.3,0.1;9.9,0.3) $5.2(9.3,0.1;9.9,0.3) 25\n"
"R $6.1(0.1,0.1;0.7,0.7) $7.2(0.1,0.1;0.7,0.7) 12.5\n"
"R $0.1(0.3,-5.7;0.5,-5.5) $2.1(9.3,-5.9;9.9,-5.3) 5.75\n"
"R $2.1(9.3,-5.9;9.9,-5.3) P0.1(12.9,-5.9;13.5,-5.3) 2.25\n"
"R $6.1(0.1,0.1;0.7,0.7) V0.1(5.2,0.4;5.2,0.4) 3\n"
"R $4.1(9.3,0.1;9.9,0.3) V0.1(5.2,0.4;5.2,0.4) 2.75\n"
"R $5.2(9.3,0.1;9.9,0.3) $8.2(10,-3.5;10,-2.7) 1.03125\n"
"R $3.2(9.3,-5.9;9.9,-5.3) $8.2(10,-3.5;10,-2.7) 0.78125\n"
"R $8.2(10,-3.5;10,-2.7) P0.2(12.9,-3.4;13.5,-2.8) 1\n"
"R $7.2(0.1,0.1;0.7,0.7) V0.2(0.4,-5.6;0.4,-5.6) 1.875\n"
"R $1.2(0.3,-5.7;0.5,-5.5) V0.2(0.4,-5.6;0.4,-5.6) 0"
);
tech.skip_simplify = false;
@ -236,11 +241,11 @@ TEST(netex_2layer)
rex.extract (tech, geo, vertex_ports, polygon_ports, network);
EXPECT_EQ (network.to_string (true),
"R $2(9.3,-5.9;9.9,-5.3) P0(12.9,-5.9;13.5,-5.3) 2.25\n"
"R $8(10,-3.5;10,-2.7) P1(12.9,-3.4;13.5,-2.8) 1\n"
"R $2(9.3,-5.9;9.9,-5.3) V1(0.3,-5.7;0.5,-5.5) 55.75\n"
"R $2(9.3,-5.9;9.9,-5.3) $8(10,-3.5;10,-2.7) 13.2813\n"
"R $8(10,-3.5;10,-2.7) V0(5.2,0.4;5.2,0.4) 28.7812\n"
"R V0(5.2,0.4;5.2,0.4) V1(0.3,-5.7;0.5,-5.5) 17.375"
"R $2.1(9.3,-5.9;9.9,-5.3) P0.1(12.9,-5.9;13.5,-5.3) 2.25\n"
"R $8.2(10,-3.5;10,-2.7) P0.2(12.9,-3.4;13.5,-2.8) 1\n"
"R $2.1(9.3,-5.9;9.9,-5.3) V0.2(0.3,-5.7;0.5,-5.5) 55.75\n"
"R $2.1(9.3,-5.9;9.9,-5.3) $8.2(10,-3.5;10,-2.7) 13.2813\n"
"R $8.2(10,-3.5;10,-2.7) V0.1(5.2,0.4;5.2,0.4) 28.7812\n"
"R V0.1(5.2,0.4;5.2,0.4) V0.2(0.3,-5.7;0.5,-5.5) 17.375"
);
}

View File

@ -69,7 +69,7 @@ TEST(basic)
std::vector<std::pair<TestableSquareCountingRExtractor::PortDefinition, pex::RNode *> > ports;
for (auto pd = pds.begin (); pd != pds.end (); ++pd) {
ports.push_back (std::make_pair (*pd, rn.create_node (pd->type, pd->port_index)));
ports.push_back (std::make_pair (*pd, rn.create_node (pd->type, pd->port_index, 0)));
}
rex.do_extract (poly, ports, rn);
@ -90,7 +90,7 @@ TEST(basic)
ports.clear ();
for (auto pd = pds.begin (); pd != pds.end (); ++pd) {
ports.push_back (std::make_pair (*pd, rn.create_node (pd->type, pd->port_index)));
ports.push_back (std::make_pair (*pd, rn.create_node (pd->type, pd->port_index, 0)));
ports.back ().first.location.transform (r90);
}