From 77aa729b0668905d089dd74b725a456e9d492a02 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 May 2025 19:45:30 +0200 Subject: [PATCH] GSI binding of RNetExtractor, introducing layers for nodes --- src/pex/pex/gsiDeclRExtractor.cc | 375 +--------------- src/pex/pex/gsiDeclRNetExtractor.cc | 393 +++++++++++++++++ src/pex/pex/gsiDeclRNetwork.cc | 412 ++++++++++++++++++ src/pex/pex/pex.pro | 2 + src/pex/pex/pexRExtractorTech.h | 4 +- src/pex/pex/pexRNetExtractor.cc | 37 +- src/pex/pex/pexRNetExtractor.h | 2 - src/pex/pex/pexRNetwork.cc | 23 +- src/pex/pex/pexRNetwork.h | 15 +- src/pex/pex/pexSquareCountingRExtractor.cc | 2 +- src/pex/pex/pexTriangulationRExtractor.cc | 8 +- src/pex/unit_tests/pexRExtractorTests.cc | 97 ++++- src/pex/unit_tests/pexRNetExtractorTests.cc | 63 +-- .../pexSquareCountingRExtractorTests.cc | 4 +- 14 files changed, 962 insertions(+), 475 deletions(-) create mode 100644 src/pex/pex/gsiDeclRNetExtractor.cc create mode 100644 src/pex/pex/gsiDeclRNetwork.cc diff --git a/src/pex/pex/gsiDeclRExtractor.cc b/src/pex/pex/gsiDeclRExtractor.cc index 8aadb05d3..a92fa42ec 100644 --- a/src/pex/pex/gsiDeclRExtractor.cc +++ b/src/pex/pex/gsiDeclRExtractor.cc @@ -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 (mp_ptr); - } - -private: - tl::weak_ptr 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 (mp_ptr); - } - -private: - tl::weak_ptr 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_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 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 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 inject_NodeType_in_RNode (decl_NodeType.defs ()); - -Class 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 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 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" ); } diff --git a/src/pex/pex/gsiDeclRNetExtractor.cc b/src/pex/pex/gsiDeclRNetExtractor.cc new file mode 100644 index 000000000..5a65f0367 --- /dev/null +++ b/src/pex/pex/gsiDeclRNetExtractor.cc @@ -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 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 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 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 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 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 *geo, + const std::map > *vertex_ports, + const std::map > *polygon_ports) +{ + std::unique_ptr network (new pex::RNetwork ()); + std::map empty_geo; + std::map > empty_vertex_ports; + std::map > 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 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" +); + +} + diff --git a/src/pex/pex/gsiDeclRNetwork.cc b/src/pex/pex/gsiDeclRNetwork.cc new file mode 100644 index 000000000..fb1c2a4f7 --- /dev/null +++ b/src/pex/pex/gsiDeclRNetwork.cc @@ -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 (mp_ptr); + } + +private: + tl::weak_ptr 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 (mp_ptr); + } + +private: + tl::weak_ptr 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_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 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 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 inject_NodeType_in_RNode (decl_NodeType.defs ()); + +Class 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 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" +); + +} + diff --git a/src/pex/pex/pex.pro b/src/pex/pex/pex.pro index 6d69e018c..ab52eaf29 100644 --- a/src/pex/pex/pex.pro +++ b/src/pex/pex/pex.pro @@ -7,6 +7,8 @@ include($$PWD/../../lib.pri) DEFINES += MAKE_PEX_LIBRARY SOURCES = \ + gsiDeclRNetExtractor.cc \ + gsiDeclRNetwork.cc \ pexForceLink.cc \ pexRExtractor.cc \ gsiDeclRExtractor.cc \ diff --git a/src/pex/pex/pexRExtractorTech.h b/src/pex/pex/pexRExtractorTech.h index c833e666a..6062910ae 100644 --- a/src/pex/pex/pexRExtractorTech.h +++ b/src/pex/pex/pexRExtractorTech.h @@ -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 }; /** diff --git a/src/pex/pex/pexRNetExtractor.cc b/src/pex/pex/pexRNetExtractor.cc index 4233a4571..e93d6e745 100644 --- a/src/pex/pex/pexRNetExtractor.cc +++ b/src/pex/pex/pexRNetExtractor.cc @@ -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 empty_vertex_ports; @@ -98,7 +85,7 @@ RNetExtractor::extract (const RExtractorTech &tech, const std::vector &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 > &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 *vertex_ports, - unsigned int vertex_port_index_offset, const std::vector *polygon_ports, - unsigned int polygon_port_index_offset, const std::vector *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 *mp_via_ports; std::map 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 ®ion, const std::vector &vertex_ports, - unsigned int vertex_ports_index_offset, const std::vector &polygon_ports, - unsigned int polygon_ports_index_offset, const std::vector &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::box_convert ()); } diff --git a/src/pex/pex/pexRNetExtractor.h b/src/pex/pex/pexRNetExtractor.h index 20ea0ab77..befd52384 100644 --- a/src/pex/pex/pexRNetExtractor.h +++ b/src/pex/pex/pexRNetExtractor.h @@ -84,9 +84,7 @@ protected: void extract_conductor (const RExtractorTechConductor &cond, const db::Region ®ion, const std::vector &vertex_ports, - unsigned int vertex_ports_index_offset, const std::vector &polygon_ports, - unsigned int polygon_ports_index_offset, const std::vector &via_ports, RNetwork &rnetwork); diff --git a/src/pex/pex/pexRNetwork.cc b/src/pex/pex/pexRNetwork.cc index 435590d81..f64c60360 100644 --- a/src/pex/pex/pexRNetwork.cc +++ b/src/pex/pex/pexRNetwork.cc @@ -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; diff --git a/src/pex/pex/pexRNetwork.h b/src/pex/pex/pexRNetwork.h index 45f4ec36a..b9438b0d9 100644 --- a/src/pex/pex/pexRNetwork.h +++ b/src/pex/pex/pexRNetwork.h @@ -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 (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, RElement *> m_elements_by_nodes; - std::map, RNode *> m_nodes_by_type; + std::map >, RNode *> m_nodes_by_type; RNetwork (const RNetwork &); RNetwork &operator= (const RNetwork &); diff --git a/src/pex/pex/pexSquareCountingRExtractor.cc b/src/pex/pex/pexSquareCountingRExtractor.cc index 1abf32d95..cd956a703 100644 --- a/src/pex/pex/pexSquareCountingRExtractor.cc +++ b/src/pex/pex/pexSquareCountingRExtractor.cc @@ -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; } diff --git a/src/pex/pex/pexTriangulationRExtractor.cc b/src/pex/pex/pexTriangulationRExtractor.cc index 18f2e70da..6a867ef43 100644 --- a/src/pex/pex/pexTriangulationRExtractor.cc +++ b/src/pex/pex/pexTriangulationRExtractor.cc @@ -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); diff --git a/src/pex/unit_tests/pexRExtractorTests.cc b/src/pex/unit_tests/pexRExtractorTests.cc index 6e04a6f6a..35ab0169a 100644 --- a/src/pex/unit_tests/pexRExtractorTests.cc +++ b/src/pex/unit_tests/pexRExtractorTests.cc @@ -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); diff --git a/src/pex/unit_tests/pexRNetExtractorTests.cc b/src/pex/unit_tests/pexRNetExtractorTests.cc index 00c8143ef..9b4d0bd49 100644 --- a/src/pex/unit_tests/pexRNetExtractorTests.cc +++ b/src/pex/unit_tests/pexRNetExtractorTests.cc @@ -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 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" ); } diff --git a/src/pex/unit_tests/pexSquareCountingRExtractorTests.cc b/src/pex/unit_tests/pexSquareCountingRExtractorTests.cc index 3da3d7b58..e3b6e057e 100644 --- a/src/pex/unit_tests/pexSquareCountingRExtractorTests.cc +++ b/src/pex/unit_tests/pexSquareCountingRExtractorTests.cc @@ -69,7 +69,7 @@ TEST(basic) std::vector > 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); }