Merge pull request #761 from KLayout/fill-debugging

Fill debugging
This commit is contained in:
Matthias Köfferlein 2021-04-03 15:33:34 +02:00 committed by GitHub
commit d9ab2ed1a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 126 additions and 47 deletions

View File

@ -212,11 +212,6 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row_step x column_step vector vector product must be > 0")));
}
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
if (enhanced_fill && ! glue_box.empty () && ! fp0.box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
enhanced_fill = false;
}
db::Vector kernel_origin (fc_bbox.left (), fc_bbox.bottom ());
std::vector <db::Polygon> filled_regions;
@ -256,13 +251,21 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
continue;
}
size_t ninsts = 0;
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
bool ef = enhanced_fill;
if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
ef = false;
}
// pick a heuristic "good" starting point in enhanced mode
// TODO: this is a pretty weak optimization.
db::Point o = origin;
if (enhanced_fill) {
if (ef) {
o = fp->hull () [0];
}
size_t ninsts = 0;
GenericRasterizer am (*fp, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
for (unsigned int i = 0; i < am.area_maps (); ++i) {
@ -454,7 +457,7 @@ fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell
DB_PUBLIC void
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box)
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
{
const db::Region *fill_region = &fr;
@ -468,7 +471,7 @@ fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fi
++iteration;
remaining.clear ();
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, origin, true, &remaining, fill_margin, remaining_polygons, iteration, glue_box);
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box);
new_fill_region.swap (remaining);
fill_region = &new_fill_region;

View File

@ -118,6 +118,6 @@ fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell
DB_PUBLIC void
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Point &origin = db::Point (), const db::Box &glue_box = db::Box ());
const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
}

View File

@ -1312,9 +1312,9 @@ fill_region_skew (db::Cell *cell, const db::Region &fr, db::cell_index_type fill
static void
fill_region_multi (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box)
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
{
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box);
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
}
static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t)
@ -1881,7 +1881,6 @@ Class<db::Cell> decl_Cell ("db", "Cell",
gsi::arg ("column_step"),
gsi::arg ("fill_margin", db::Vector ()),
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
gsi::arg ("origin", db::Point ()),
gsi::arg ("glue_box", db::Box ()),
"@brief Fills the given region with cells of the given type in enhanced mode with iterations\n"
"This version operates like \\fill_region, but repeats the fill generation until no further fill cells can be placed. "

View File

@ -1349,12 +1349,14 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"This method is provided to ensure this explicitly. This can be useful while using \\start_changes and \\end_changes to wrap a performance-critical operation. "
"See \\start_changes for more details."
) +
gsi::method ("cleanup", &db::Layout::cleanup,
gsi::method ("cleanup", &db::Layout::cleanup, gsi::arg ("cell_indexes_to_keep", std::set<db::cell_index_type> (), "[]"),
"@brief Cleans up the layout\n"
"This method will remove proxy objects that are no longer in use. After changing PCell parameters such "
"proxy objects may still be present in the layout and are cached for later reuse. Usually they are cleaned up automatically occasionally, "
"proxy objects may still be present in the layout and are cached for later reuse. Usually they are cleaned up automatically, "
"but in a scripting context it may be useful to clean up these cells explicitly.\n"
"\n"
"Use 'cell_indexes_to_keep' for specifying a list of cell indexes of PCell variants or library proxies you don't want to be cleaned up.\n"
"\n"
"This method has been introduced in version 0.25.\n"
) +
gsi::method ("dbu=", (void (db::Layout::*) (double)) &db::Layout::dbu, gsi::arg ("dbu"),

View File

@ -730,9 +730,9 @@ fill_region_skew (const db::Region *fr, db::Cell *cell, db::cell_index_type fill
static void
fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box)
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
{
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box);
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
}
static db::Point default_origin;
@ -2921,7 +2921,6 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
gsi::arg ("column_step"),
gsi::arg ("fill_margin", db::Vector ()),
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
gsi::arg ("origin", db::Point ()),
gsi::arg ("glue_box", db::Box ()),
"@brief A mapping of \\Cell#fill_region to the Region class\n"
"\n"

View File

@ -259,6 +259,10 @@ module DRC
DRCFillOrigin::new
end
def multi_origin
DRCFillOrigin::new(nil, nil, true)
end
def origin(x, y)
DRCFillOrigin::new(x, y)
end

View File

@ -4251,7 +4251,9 @@ CODE
# @li @b origin(x, y) @/b: specifies a fixed point to align the pattern with. This point specifies the location
# of the reference point for one pattern cell. @/li
# @li @b auto_origin @/b: lets the algorithm choose the origin. This may result is a slightly better fill coverage
# as the algorithm is able to determine a pattern origin per fill island. @/li
# as the algorithm is able to determine a pattern origin per island to fill. @/li
# @li @b multi_origin @/b: lets the algorithm choose the origin and repeats the fill with different origins
# until no further fill cell can be fitted. @/li
# @li @b fill_pattern(..) @/b: specifies the fill pattern. @/li
# @/ul
#
@ -4355,6 +4357,7 @@ CODE
column_step = nil
pattern = nil
origin = RBA::DPoint::new
repeat = false
args.each_with_index do |a,ai|
if a.is_a?(DRCSource)
@ -4381,6 +4384,7 @@ CODE
end
elsif a.is_a?(DRCFillOrigin)
origin = a.origin
repeat = a.repeat
else
raise("Argument ##{ai+1} not understood for '#{m}'")
end
@ -4435,31 +4439,22 @@ CODE
tp.var("cs", cs)
tp.var("origin", origin)
tp.var("fc_index", fc_index)
tp.var("repeat", repeat)
tp.var("with_left", with_left)
if with_left
tp.queue(<<"END")
var tc_box = _frame.bbox;
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
!tile_box.empty && (
tile_box = tile_box.enlarged(Vector.new(max(rs.x, fc_box.width), max(cs.y, fc_box.height)));
tile_box = tile_box & tc_box;
var left = Region.new;
tp.queue(<<"END")
var tc_box = _frame.bbox;
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
!tile_box.empty && (
tile_box = tile_box.enlarged(Vector.new(max(rs.x, fc_box.width), max(cs.y, fc_box.height)));
tile_box = tile_box & tc_box;
var left = with_left ? Region.new : nil;
repeat ?
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, Vector.new, left, _tile.bbox) :
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox);
_output(#{result_arg}, left)
)
with_left && _output(#{result_arg}, left)
)
END
else
tp.queue(<<"END")
var tc_box = _frame.bbox;
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
!tile_box.empty && (
tile_box.right = tile_box.right + rs.x - 1;
tile_box.top = tile_box.top + cs.y - 1;
tile_box = tile_box & tc_box;
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, nil, Vector.new, nil, _tile.bbox)
)
END
end
begin
@engine._output_layout.start_changes
@ -4477,10 +4472,19 @@ END
end
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
if repeat
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, RBA::Vector::new, result)
else
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
end
end
end
if fill_cell.parent_cells == 0
# fill cell not required (not placed) -> remove
fill_cell.delete
end
self.data.disable_progress

View File

@ -334,7 +334,8 @@ module DRC
# A wrapper for the fill origin definition
class DRCFillOrigin
def initialize(x = nil, y = nil)
def initialize(x = nil, y = nil, repeat = false)
@repeat = repeat
if !x && !y
@origin = nil
else
@ -350,6 +351,9 @@ module DRC
def origin
@origin
end
def repeat
@repeat
end
end
# A wrapper for the tile_size option

View File

@ -1222,3 +1222,13 @@ TEST(45_fillWithOverlappingBoxesTiled)
{
run_test (_this, "45", false);
}
TEST(46_fillWithOverlappingBoxes)
{
run_test (_this, "46", false);
}
TEST(47_fillWithOverlappingBoxesTiled)
{
run_test (_this, "47", false);
}

View File

@ -1044,7 +1044,9 @@ a positive value. A horizontal displacement component can be specified too, whic
<li><b>origin(x, y) </b>: specifies a fixed point to align the pattern with. This point specifies the location
of the reference point for one pattern cell. </li>
<li><b>auto_origin </b>: lets the algorithm choose the origin. This may result is a slightly better fill coverage
as the algorithm is able to determine a pattern origin per fill island. </li>
as the algorithm is able to determine a pattern origin per island to fill. </li>
<li><b>multi_origin </b>: lets the algorithm choose the origin and repeats the fill with different origins
until no further fill cell can be fitted. </li>
<li><b>fill_pattern(..) </b>: specifies the fill pattern. </li>
</ul>
</p><p>

View File

@ -835,9 +835,9 @@ Class<lay::LayerProperties> decl_LayerProperties ("lay", "LayerProperties",
"If the layer index is positive, the shapes drawn are taken from this layer rather than "
"searched for by layer and datatype. This property is stronger than the layer/datatype or "
"name specification.\n\n"
"The similar method \\layer_index "
"returns the actual layer index used, not the given one. The latter may be negative indicating "
"that layer/datatype or name specifications are used.\n\n"
"A different method is \\layer_index which indicates the ID of the layer actually used. "
"While \"source_layer_index\" is one of several ways to address the layer drawn, \"layer_index\" is the ID (index) "
"of the layer matching the source specification and is >= 0 if such a layer is found.\n\n"
"If \"real\" is true, the effective value is returned."
) +
method_ext ("source_layer_index", &get_layer_index_1,

25
testdata/drc/drcSimpleTests_46.drc vendored Normal file
View File

@ -0,0 +1,25 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l1.output(1, 0)
to_fill = extent - l1
fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm)
to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin)
fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm)
to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin)
fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm)
to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin)
to_fill.output(100, 0)

BIN
testdata/drc/drcSimpleTests_46.gds vendored Normal file

Binary file not shown.

27
testdata/drc/drcSimpleTests_47.drc vendored Normal file
View File

@ -0,0 +1,27 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
tiles(20, 20)
l1 = input(1, 0)
l1.output(1, 0)
to_fill = extent - l1
fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm)
to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin)
fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm)
to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin)
fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm)
to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin)
to_fill.output(100, 0)

BIN
testdata/drc/drcSimpleTests_47.gds vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au46.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au47.gds vendored Normal file

Binary file not shown.