Cell variant resolution by propagation, grid check now implementation hierarchically (with propagation)

This commit is contained in:
Matthias Koefferlein 2019-02-17 10:59:04 +01:00
parent 5dc833970b
commit a7bfaac424
11 changed files with 319 additions and 3 deletions

View File

@ -28,6 +28,7 @@
#include "dbLayout.h"
#include "dbTrans.h"
#include "tlTypeTraits.h"
#include "tlUtils.h"
namespace db
{
@ -354,6 +355,123 @@ public:
}
}
/**
* @brief Commits the shapes for different variants to the current cell hierarchy
*
* This is an alternative approach and will push the variant shapes into the parent hierarchy.
* "to_commit" initially is a set of shapes to commit for the given cell and variant.
* This map is modified during the algorithm and should be discarded later.
*/
virtual void commit_shapes (db::Layout &layout, db::Cell &top_cell, unsigned int layer, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
{
if (to_commit.empty ()) {
return;
}
// NOTE: this implementation suffers from accumulation of propagated shapes: we add more levels of propagated
// shapes if required. We don't clean up, because we do not know when a shape collection stops being required.
db::LayoutLocker locker (&layout);
std::set<db::cell_index_type> called;
top_cell.collect_called_cells (called);
called.insert (top_cell.cell_index ());
for (db::Layout::bottom_up_const_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) {
if (called.find (*c) == called.end ()) {
continue;
}
db::Cell &cell = layout.cell (*c);
std::map<db::ICplxTrans, size_t> &vvc = m_variants [*c];
if (vvc.size () > 1) {
for (std::map<db::ICplxTrans, size_t>::const_iterator vc = vvc.begin (); vc != vvc.end (); ++vc) {
for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) {
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::const_iterator tc = to_commit.find (i->cell_index ());
if (tc != to_commit.end ()) {
const std::map<db::ICplxTrans, db::Shapes> &vt = tc->second;
// NOTE: this will add one more commit slot for propagation ... but we don't clean up.
// When would a cleanup happen?
std::map<db::ICplxTrans, db::Shapes> &propagated = to_commit [*c];
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
db::ICplxTrans t = i->complex_trans (*ia);
db::ICplxTrans rt = m_red (vc->first * t);
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
if (v != vt.end ()) {
db::Shapes &ps = propagated [vc->first];
tl::ident_map<db::Layout::properties_id_type> pm;
for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
ps.insert (*si, t, pm);
}
}
}
}
}
}
} else {
// single variant -> we can commit any shapes we have kept for this cell directly to the cell
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::iterator l = to_commit.find (*c);
if (l != to_commit.end ()) {
tl_assert (l->second.size () == 1);
cell.shapes (layer).insert (l->second.begin ()->second);
to_commit.erase (l);
}
// for child cells, pull everything that needs to be committed to the parent
for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) {
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::const_iterator tc = to_commit.find (i->cell_index ());
if (tc != to_commit.end ()) {
const std::map<db::ICplxTrans, db::Shapes> &vt = tc->second;
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
db::ICplxTrans t = i->complex_trans (*ia);
db::ICplxTrans rt = m_red (vvc.begin ()->first * t);
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
if (v != vt.end ()) {
tl::ident_map<db::Layout::properties_id_type> pm;
for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
cell.shapes (layer).insert (*si, t, pm);
}
}
}
}
}
}
}
}
/**
* @brief Gets the variants for a given cell
*
@ -371,6 +489,19 @@ public:
}
}
/**
* @brief Returns true, if variants have been built
*/
bool has_variants () const
{
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> >::const_iterator i = m_variants.begin (); i != m_variants.end (); ++i) {
if (i->second.size () > 1) {
return true;
}
}
return false;
}
private:
std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> > m_variants;
Reduce m_red;

View File

@ -713,11 +713,82 @@ DeepRegion::to_string (size_t nmax) const
return db::AsIfFlatRegion::to_string (nmax);
}
static void produce_offgrid_markers (db::Shapes &markers, const db::Shapes &shapes, const db::ICplxTrans &tr, db::Coord g)
{
for (db::Shapes::shape_iterator si = shapes.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly;
si->polygon (poly);
for (size_t i = 0; i < poly.holes () + 1; ++i) {
db::Polygon::polygon_contour_iterator b, e;
if (i == 0) {
b = poly.begin_hull ();
e = poly.end_hull ();
} else {
b = poly.begin_hole ((unsigned int) (i - 1));
e = poly.end_hole ((unsigned int) (i - 1));
}
for (db::Polygon::polygon_contour_iterator p = b; p != e; ++p) {
db::Point pt = tr * *p;
if ((pt.x () % g) != 0 || (pt.y () % g) != 0) {
markers.insert (EdgePair (db::Edge (pt, pt), db::Edge (pt, pt)));
}
}
}
}
}
EdgePairs
DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
{
// TODO: snap be optimized by forming grid variants etc.
return db::AsIfFlatRegion::grid_check (gx, gy);
if (gx <= 0 || gy <= 0) {
throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value")));
}
if (gx != gy) {
// no way doing this hierarchically ?
return db::AsIfFlatRegion::grid_check (gx, gy);
}
ensure_merged_polygons_valid ();
db::Layout &layout = m_merged_polygons.layout ();
db::cell_variants_collector<db::GridReducer> vars (gx);
vars.collect (layout, m_merged_polygons.initial_cell ());
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
std::auto_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (m_merged_polygons.derived ()));
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const std::map<db::ICplxTrans, size_t> &vv = vars.variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *markers;
if (vv.size () == 1) {
markers = & c->shapes (res->deep_layer ().layer ());
} else {
markers = & to_commit [c->cell_index ()] [v->first];
}
produce_offgrid_markers (*markers, c->shapes (m_merged_polygons.layer ()), v->first, gx);
}
}
// propagate the markers with a similar algorithm used for producing the variants
res->deep_layer ().commit_shapes (vars, to_commit);
return db::EdgePairs (res.release ());
}
EdgePairs

View File

@ -159,6 +159,19 @@ public:
template <class VarCollector>
void separate_variants (VarCollector &collector);
/**
* @brief Commits shapes for variants to the existing cell hierarchy
*
* The "to_propagate" collection is a set of shapes per cell and variant. The
* algorithm will put these shapes into the existing hierarchy putting the
* shapes into the proper parent cells to resolve variants.
*
* This map will be modified by the algorithm and should be discarded
* later.
*/
template <class VarCollector>
void commit_shapes (VarCollector &collector, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_propagate);
/**
* @brief Gets the shape store object
* This is a pure const version to prevent manipulation of the store.
@ -299,6 +312,21 @@ public:
issue_variants (layout_index, var_map);
}
/**
* @brief Commits shapes for variants to the existing cell hierarchy
*
* To use this method, first create a variant collector (db::cell_variant_collector) with the required
* reducer and collect the variants. Then call this method on the desired layout index to commit the shapes for the
* respective variants.
*/
template <class VarCollector>
void commit_shapes (unsigned int layout_index, VarCollector &coll, unsigned int layer, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
{
tl_assert (is_valid_layout_index (layout_index));
coll.commit_shapes (layout (layout_index), initial_cell (layout_index), layer, to_commit);
}
/**
* @brief For testing
*/
@ -538,6 +566,13 @@ void DeepLayer::separate_variants (VarCollector &collector)
mp_store->separate_variants (m_layout, collector);
}
template <class VarCollector>
void DeepLayer::commit_shapes (VarCollector &collector, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
{
check_dss ();
mp_store->commit_shapes (m_layout, collector, layer (), to_commit);
}
}
namespace tl

View File

@ -392,3 +392,47 @@ TEST(100_OrientationVariantsWithLayout)
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au1.gds");
}
TEST(101_Propagation)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/cell_variants_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
unsigned int l2 = ly.insert_layer (db::LayerProperties (2, 0));
db::cell_variants_collector<db::MagnificationAndOrientationReducer> vb;
vb.collect (ly, top_cell);
for (db::Layout::const_iterator c = ly.begin (); c != ly.end (); ++c) {
const std::map<db::ICplxTrans, size_t> &vv = vb.variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
db::Shapes &out = to_commit [c->cell_index ()][v->first];
for (db::Shapes::shape_iterator s = c->shapes (l1).begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
db::Box b = s->bbox ().transformed (v->first);
b.enlarge (db::Vector (-100, 0));
out.insert (b.transformed (v->first.inverted ()));
}
}
}
vb.commit_shapes (ly, top_cell, l2, to_commit);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au2.gds");
}

View File

@ -969,7 +969,7 @@ TEST(17_SinglePolygonChecks)
}
}
TEST(18_Checks)
TEST(18_MultiPolygonChecks)
{
db::Layout ly;
{
@ -1013,6 +1013,41 @@ TEST(18_Checks)
}
}
TEST(19_GridCheck)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/deep_region_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
db::DeepShapeStore dss;
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Region r3_gc1;
r3.grid_check (25, 25).polygons (r3_gc1, 100);
db::Region r3_gc2;
r3.grid_check (40, 40).polygons (r3_gc2, 100);
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r3_gc1);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r3_gc2);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au19.gds");
}
TEST(100_Integration)
{
db::Layout ly;

BIN
testdata/algo/cell_variants_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/cell_variants_l1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_region_au14b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_region_au17.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_region_au18.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_region_au19.gds vendored Normal file

Binary file not shown.