Added multi-cell mapping for transferring multiple cells from one layout to another while including their hierarchy without duplicating cells.

This commit is contained in:
Matthias Koefferlein 2020-08-29 10:07:17 +02:00
parent 7f04ace865
commit 7d3abce201
6 changed files with 205 additions and 18 deletions

View File

@ -276,7 +276,19 @@ CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_in
map (cell_index_b, cell_index_a);
}
void
void
CellMapping::create_multi_mapping (const db::Layout & /*layout_a*/, const std::vector<db::cell_index_type> &cell_index_a, const db::Layout & /*layout_b*/, const std::vector<db::cell_index_type> &cell_index_b)
{
clear ();
if (cell_index_a.size () != cell_index_b.size ()) {
throw tl::Exception (tl::to_string (tr ("cell index arrays for A and B cells must have same length in 'create_multi_mapping'")));
}
for (std::vector<db::cell_index_type>::const_iterator ia = cell_index_a.begin (), ib = cell_index_b.begin (); ia != cell_index_a.end (); ++ia, ++ib) {
map (*ib, *ia);
}
}
void
CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b)
{
clear ();
@ -295,31 +307,33 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type
}
std::vector<db::cell_index_type>
CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
CellMapping::create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
{
std::vector<db::cell_index_type> new_cells;
do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0);
do_create_missing_mapping (layout_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0);
return new_cells;
}
std::vector<std::pair<db::cell_index_type, db::cell_index_type> >
CellMapping::create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
CellMapping::create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
{
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > cell_pairs;
do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs);
do_create_missing_mapping (layout_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs);
return cell_pairs;
}
void
CellMapping::do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells_ptr, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs)
CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells_ptr, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs)
{
std::vector<db::cell_index_type> new_cells_int;
std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int);
std::vector<db::cell_index_type> new_cells_b;
std::set<db::cell_index_type> called_b;
layout_b.cell (cell_index_b).collect_called_cells (called_b);
called_b.insert (cell_index_b);
for (std::vector<db::cell_index_type>::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) {
layout_b.cell (*i).collect_called_cells (called_b);
called_b.insert (*i);
}
for (std::set<db::cell_index_type>::const_iterator b = called_b.begin (); b != called_b.end (); ++b) {
if (m_b2a_mapping.find (*b) == m_b2a_mapping.end ()

View File

@ -81,7 +81,30 @@ public:
std::vector<db::cell_index_type> create_single_mapping_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b)
{
create_single_mapping (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, layout_b, cell_index_b);
}
/**
* @brief Create a multi-cell mapping
*
* The mapping created by this function will map the cells of cell_indexes_b to cell_indexes_a. Both arrays need to have
* the same length.
* This cell mapping will not map the child cells. When used for hierarchical copy this will basically
* flatten the cells on copy.
*/
void create_multi_mapping (const db::Layout &layout_a, const std::vector<db::cell_index_type> &cell_indexes_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_indexes_b);
/**
* @brief Create a single cell full mapping
*
* The mapping created by this function will map the cells of cell_indexes_a to cell_indexes_b. Both arrays need to have
* the same length. In addition, new cells for the child cells of all cell_indexes_b cells are created in layout_a and
* included in the mapping.
*/
std::vector<db::cell_index_type> create_multi_mapping_full (db::Layout &layout_a, const std::vector<db::cell_index_type> &cell_indexes_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_indexes_b)
{
create_multi_mapping (layout_a, cell_indexes_a, layout_b, cell_indexes_b);
return create_missing_mapping (layout_a, layout_b, cell_indexes_b);
}
/**
@ -100,7 +123,7 @@ public:
std::vector<db::cell_index_type> create_from_geometry_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b)
{
create_from_geometry (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, layout_b, cell_index_b);
}
/**
@ -119,7 +142,7 @@ public:
std::vector<db::cell_index_type> create_from_names_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b)
{
create_from_names (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b);
return create_missing_mapping (layout_a, layout_b, cell_index_b);
}
/**
@ -184,8 +207,9 @@ public:
/**
* @brief Creates mappings for all cells not mapped yet
*
* When constructing a cell mapping by explicit mapping (map (a, b)), some cells may be
* left unmapped. This method allows creating mappings for these missing cells by adding
* When constructing a cell mapping by explicit mapping (map (a, b)), some child cells of the
* mapped other cells may be left unmapped.
* This method allows creating mappings for these missing cells by adding
* new cells and the corresponding instances into the target layout_a.
*
* If given, "exclude_cells" can specify a list of cells not to map.
@ -195,7 +219,18 @@ public:
*
* The returned vector lists the new cells.
*/
std::vector<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
std::vector<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
/**
* @brief A convenience version of create_missing_mappings which takes a single cell for cell_index_a and cell_index_b.
*/
std::vector<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0)
{
std::vector<db::cell_index_type> cib;
cib.reserve (1);
cib.push_back (cell_index_b);
return create_missing_mapping (layout_a, layout_b, cib, exclude_cells, include_cells);
}
/**
* @brief Like create_missing_mapping, but returns the newly mapped pairs
@ -203,7 +238,21 @@ public:
* The first cell index of the pair is the old cell in layout_a, the second cell index
* is the new cell in layout_b.
*/
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
/**
* @brief Like create_missing_mapping, but returns the newly mapped pairs (single-cell version)
*
* The first cell index of the pair is the old cell in layout_a, the second cell index
* is the new cell in layout_b.
*/
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0)
{
std::vector<db::cell_index_type> cib;
cib.reserve (1);
cib.push_back (cell_index_b);
return create_missing_mapping2 (layout_a, layout_b, cib, exclude_cells, include_cells);
}
private:
void extract_unique (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::const_iterator cand,
@ -213,7 +262,7 @@ private:
void dump_mapping (const std::map <db::cell_index_type, std::vector<db::cell_index_type> > &candidates,
const db::Layout &layout_a, const db::Layout &layout_b);
void do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs);
void do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs);
std::map <db::cell_index_type, db::cell_index_type> m_b2a_mapping;
};

View File

@ -977,7 +977,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
// Add new cells for the variants and (possible) devices which are cells added during the device
// extraction process
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells);
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, *source_layout, source_top, excluded_cells, included_cells);
// the variant's originals we are going to delete
std::set<db::cell_index_type> cells_to_delete;

View File

@ -76,10 +76,42 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
"The cell mapping is created for cell_b to cell_a in the respective layouts. "
"This method clears the mapping and creates one for the single cell pair. "
"In addition and in contrast to \\for_single_cell, this method completes the mapping by adding all the child cells "
"of cell_b to layout_a and creating the proper instances. "
"of cell_b to layout_a and creating the proper instances.\n"
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method ("for_multi_cells", &db::CellMapping::create_multi_mapping, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"),
"@brief Initializes the cell mapping for top-level identity\n"
"\n"
"@param layout_a The target layout.\n"
"@param cell_indexes_a A list of cell indexes for the target cells.\n"
"@param layout_b The source layout.\n"
"@param cell_indexes_b A list of cell indexes for the source cells (same number of indexes than \\cell_indexes_a).\n"
"\n"
"The cell mapping is created for cells from cell_indexes_b to cell from cell_indexes_a in the respective layouts. "
"This method clears the mapping and creates one for each cell pair from cell_indexes_b vs. cell_indexes_a. "
"If used for \\Layout#copy_tree or \\Layout#move_tree, this cell mapping will essentially "
"flatten the source cells in the target layout.\n"
"\n"
"This method is equivalent to \\clear, followed by \\map(cell_index_a, cell_index_b) for each cell pair.\n"
"\n"
"This method has been introduced in version 0.27."
) +
gsi::method ("for_multi_cells_full", &db::CellMapping::create_multi_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"),
"@brief Initializes the cell mapping for top-level identity\n"
"\n"
"@param layout_a The target layout.\n"
"@param cell_indexes_a A list of cell indexes for the target cells.\n"
"@param layout_b The source layout.\n"
"@param cell_indexes_b A list of cell indexes for the source cells (same number of indexes than \\cell_indexes_a).\n"
"\n"
"The cell mapping is created for cells from cell_indexes_b to cell from cell_indexes_a in the respective layouts. "
"This method clears the mapping and creates one for each cell pair from cell_indexes_b vs. cell_indexes_a. "
"In addition and in contrast to \\for_multi_cells, this method completes the mapping by adding all the child cells "
"of all cells in cell_indexes_b to layout_a and creating the proper instances.\n"
"\n"
"This method has been introduced in version 0.27."
) +
gsi::method ("from_geometry_full", &db::CellMapping::create_from_geometry_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
"@brief Initializes the cell mapping using the geometrical identity in full mapping mode\n"
"\n"
@ -234,6 +266,26 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
"\n"
"CellMapping objects play a role mainly in the hierarchical copy or move operations of \\Layout. "
"However, use is not restricted to these applications.\n"
"\n"
"Here is one example for using \\CellMapping. It extracts cells 'A', 'B' and 'C' from one layout "
"and copies them to another. It will also copy all shapes and all child cells. Child cells which are "
"shared between the three initial cells will be shared in the target layout too.\n"
"\n"
"@code\n"
"cell_names = [ \"A\", \"B\", \"C\" ]\n"
"\n"
"source = RBA::Layout::new\n"
"source.read(\"input.gds\")\n"
"\n"
"target = RBA::Layout::new\n"
"\n"
"source_cells = cell_names.collect { |n| source.cell_by_name(n).cell_index }\n"
"target_cells = cell_names.collect { |n| target.create_cell(n).cell_index }\n"
"\n"
"cm = RBA::CellMapping::new\n"
"cm.for_multi_cells_full(source, source_cells, target, target_cells)\n"
"target.copy_tree_shapes(source, cm)\n"
"@/code\n"
);
}

View File

@ -453,3 +453,40 @@ TEST(6)
EXPECT_EQ (l2s (h), "a0top#0:cell_index=1 r90 0,0 array=(0,10,10,0 5x2),cell_index=2 r90 0,0 array=(0,10,10,0 5x2);a4#1:;a5#2:");
}
// Multi-mapping
TEST(7)
{
std::auto_ptr<db::Layout> g (new db::Layout ());
db::Cell &a0 (g->cell (g->add_cell ("a0")));
db::Cell &a1 (g->cell (g->add_cell ("a1")));
db::Cell &a2 (g->cell (g->add_cell ("a2")));
db::Cell &a3 (g->cell (g->add_cell ("a3")));
db::Cell &a4 = g->cell (g->add_cell ("a4"));
db::Cell &a5 = g->cell (g->add_cell ("a5"));
a3.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ()));
a3.insert (db::CellInstArray (db::CellInst (a5.cell_index ()), db::Trans ()));
a1.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ()));
a1.insert (db::CellInstArray (db::CellInst (a3.cell_index ()), db::Trans ()));
a2.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ()));
db::Layout h;
db::Cell &b0 (h.cell (h.add_cell ("b0")));
db::Cell &b1 (h.cell (h.add_cell ("b1")));
db::Cell &b2 (h.cell (h.add_cell ("b2")));
db::CellMapping cm;
std::vector<db::cell_index_type> cib, cia;
cia.push_back (a0.cell_index ());
cia.push_back (a1.cell_index ());
cia.push_back (a2.cell_index ());
cib.push_back (b0.cell_index ());
cib.push_back (b1.cell_index ());
cib.push_back (b2.cell_index ());
cm.create_multi_mapping_full (h, cib, *g, cia);
EXPECT_EQ (m2s (cm, *g, h), "a0->b0;a1->b1;a2->b2;a3->a3;a4->a4;a5->a5");
EXPECT_EQ (l2s (h), "b0#0:;b1#1:cell_index=3 r0 0,0,cell_index=4 r0 0,0;b2#2:cell_index=4 r0 0,0;a3#3:cell_index=4 r0 0,0,cell_index=5 r0 0,0;a4#4:;a5#5:");
}

View File

@ -205,6 +205,41 @@ class DBCellMapping_TestClass < TestBase
end
def test_2
ly = RBA::Layout::new
a0 = ly.create_cell("a0")
a1 = ly.create_cell("a1")
a2 = ly.create_cell("a2")
a3 = ly.create_cell("a3")
a4 = ly.create_cell("a4")
a5 = ly.create_cell("a5")
a3.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new))
a3.insert(RBA::CellInstArray::new(a5.cell_index, RBA::Trans::new))
a1.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new))
a1.insert(RBA::CellInstArray::new(a3.cell_index, RBA::Trans::new))
a2.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new))
ly_target = RBA::Layout::new
b0 = ly_target.create_cell("b0")
b1 = ly_target.create_cell("b1")
b2 = ly_target.create_cell("b2")
cm = RBA::CellMapping::new
cm.for_multi_cells(ly_target, [ b0, b1, b2 ].collect { |c| c.cell_index }, ly, [ a0, a1, a2 ].collect { |c| c.cell_index })
assert_equal(mapping_to_s(ly_target, ly, cm), "b0=>a0;b1=>a1;b2=>a2")
cm = RBA::CellMapping::new
cm.for_multi_cells_full(ly_target, [ b0, b1, b2 ].collect { |c| c.cell_index }, ly, [ a0, a1, a2 ].collect { |c| c.cell_index })
assert_equal(mapping_to_s(ly_target, ly, cm), "b0=>a0;b1=>a1;b2=>a2;a3=>a3;a4=>a4;a5=>a5")
end
end
load("test_epilogue.rb")