Fixing doc

This commit is contained in:
Matthias Koefferlein 2025-08-03 15:23:49 +02:00
parent 642cbd6831
commit bade7489d8
5 changed files with 365 additions and 56 deletions

View File

@ -722,6 +722,15 @@ actual edges from the first input (see <a href="#separation">separation</a> for
<p>
Similar to <a href="#log">log</a>, but the message is printed formatted as an error
</p>
<a name="evaluate_nets"/><h2>"evaluate_nets" - Evaluates expressions on nets</h2>
<keyword name="evaluate_nets"/>
<p>Usage:</p>
<ul>
<li><tt>evaluate_nets(primary_layer, secondary_layers, expression [, variables])</tt></li>
</ul>
<p>
See <a href="/about/drc_ref_netter.xml#evaluate_nets">Netter#evaluate_nets</a> for a description of that function.
</p>
<a name="extent"/><h2>"extent" - Creates a new layer with the bounding box of the default source or cell bounding boxes</h2>
<keyword name="extent"/>
<p>Usage:</p>

View File

@ -967,6 +967,104 @@ The following images show the effect of the method:
</tr>
</table>
</p>
<a name="evaluate"/><h2>"evaluate" - Evaluates expressions on the shapes of the layer</h2>
<keyword name="evaluate"/>
<p>Usage:</p>
<ul>
<li><tt>layer.evaluate(expression [, variables [, keep_properties ]])</tt></li>
</ul>
<p>
Evaluates the given expression on the shapes of the layer.
The expression needs to be written in the KLayout expressions
notation.
</p><p>
The expressions can place properties on the shapes using the
"put" function. As input, the expressions will receive the
(merged) shapes in micrometer units (e.g. <class_doc href="DPolygon">DPolygon</class_doc> type)
by calling the "shape" function.
</p><p>
By default, input shapes are copied to the output with the properties
attached to them by "put". You can skip shapes by calling "skip" with
a 'true' value. In that case, the shape is not copied. This allows
implementing filters.
</p><p>
Available functions for the expressions are:
</p><p>
<ul>
<li>"put(name, value)": creates a property with the given name and value </li>
<li>"skip(flag)": if called with a 'true' value, the shape will be dropped from the output </li>
<li>"shape": the current shape in micrometer units </li>
<li>"value(name)": the value of a property with name 'name' or nil if the current shape does not have a property with this name </li>
</ul>
</p><p>
Properties with well-formed names (e.g. "VALUE") are available as
variables in the expressions as a shortcut.
</p><p>
'variables' is a hash of arbitrary names and values. Each of these values
becomes available as a variable in the expression. This eliminates the need
to build expression strings with pasted value strings for passing external values.
</p><p>
If 'keep_properties' is true, the existing properties of the shape will be kept.
Otherwise (the default), existing properties will be removed before adding new
ones with 'put'.
</p><p>
The following example computes the area of the shapes and puts them
into a property 'area':
</p><p>
<pre>
layer.evaluate(scales("put('area', shape.area)"))
</pre>
</p><p>
NOTE: GDS does not support properties with string names, so
either save to OASIS or use integer numbers for the property names.
</p><p>
The expressions require a hint
whether they make use of anisotropic or scale-dependent properties.
For example, the height of a box is an anisotropic property. If a check is made
inside a rotated cell, the height transforms to a width and the check renders
different results for the same cell, if the cell is placed rotated and non-rotated.
The solution is cell variant formation which happens automatically when the
"aniso" hint is present.
</p><p>
Similarly, if a check is made against physical dimensions, the check will have
different results for cells placed with different magnifications. Such a check
is not scale-invariant and needs to get a "scaled" hint.
</p><p>
By default it is assumed that the expressions are isotropic and scale invariant.
You can mark an expression as anisotropic and/or scale dependent using the following
expression modifiers:
</p><p>
<pre>
# isotropic and scale invariant
layer.evaluate("put('holes', shape.holes)")
# anisotropic, but scale invariant
layer.evaluate(aniso("put('aspect_ratio', shape.bbox.height/shape.bbox.width)"))
# isotropic, but not scale invariant
layer.evaluate(scales("put('area', shape.area)"))
# anisotropic and not scale invariant
layer.evaluate(aniso_and_scales("put('width', shape.bbox.width)"))
</pre>
</p><p>
If you forget to specify this hint, the expression will use the local
shape properties and fail to correctly produce the results in the presence
of deep mode and rotated or magnified cell instances.
</p><p>
The "evaluate" method modifies the input layer. A version that returns
a new layer without modifying the input is <a href="#evaluated">evaluated</a>.
</p>
<a name="evaluated"/><h2>"evaluated" - Evaluates expressions on the shapes of the layer and returns a new layer</h2>
<keyword name="evaluated"/>
<p>Usage:</p>
<ul>
<li><tt>layer.evaluated(expression [, variables [, keep_properties]])</tt></li>
</ul>
<p>
This method is the out-of-place version of <a href="#evaluate">evaluate</a>. It takes the same
arguments.
</p>
<a name="extended"/><h2>"extended" - Returns polygons describing an area along the edges of the input</h2>
<keyword name="extended"/>
<p>Usage:</p>
@ -2780,6 +2878,87 @@ is <a href="#covering">covering</a>.
</p><p>
This method is available for polygons only.
</p>
<a name="select_if"/><h2>"select_if" - Selects shapes of a layer based on the evaluation of an expression</h2>
<keyword name="select_if"/>
<p>Usage:</p>
<ul>
<li><tt>layer.select_if(expression [, variables])</tt></li>
</ul>
<p>
Evaluates the given expression on the shapes of the layer.
If the evaluation gives a 'true' value, the shape is selected. Otherwise
it is discarded.
</p><p>
The expression is written in KLayout expression notation.
</p><p>
As input, the expressions will receive the
(merged) shapes in micrometer units (e.g. <class_doc href="DPolygon">DPolygon</class_doc> type)
by calling the "shape" function.
</p><p>
Available functions are:
</p><p>
<ul>
<li>"shape": the current shape in micrometer units </li>
<li>"value(name)": the value of a property with name 'name' or nil if the current shape does not have a property with this name </li>
</ul>
</p><p>
Properties with well-formed names (e.g. "VALUE") are available as
variables in the expressions as a shortcut.
</p><p>
The expressions require a hint
whether they make use of anisotropic or scale-dependent properties.
For example, the height of a box is an anisotropic property. If a check is made
inside a rotated cell, the height transforms to a width and the check renders
different results for the same cell, if the cell is placed rotated and non-rotated.
The solution is cell variant formation which happens automatically when the
"aniso" hint is present.
</p><p>
Similarly, if a check is made against physical dimensions, the check will have
different results for cells placed with different magnifications. Such a check
is not scale-invariant and needs to get a "scaled" hint.
</p><p>
By default it is assumed that the expressions are isotropic and scale invariant.
You can mark an expression as anisotropic and/or scale dependent using the following
expression modifiers:
</p><p>
<pre>
# isotropic and scale invariant
layer.select_if("shape.holes &gt; 0")
# anisotropic, but scale invariant
layer.select_if(aniso("shape.bbox.height/shape.bbox.width &gt; 2"))
# isotropic, but not scale invariant
layer.select_if(scales("shape.area &gt; 10.0"))
# anisotropic and not scale invariant
layer.select_if(aniso_and_scales("shape.bbox.width &gt; 10.0"))
</pre>
</p><p>
If you forget to specify this hint, the expression will use the local
shape properties and fail to correctly produce the results in the presence
of deep mode and rotated or magnified cell instances.
</p><p>
'variables' is a hash of arbitrary names and values. Each of these values
becomes available as a variable in the expression. This eliminates the need
to build expression strings with pasted value strings for passing external values.
</p><p>
The following example selects all shapes on the layer with an area
less than 10 square micrometers:
</p><p>
<pre>
layer.select(scales("shape.area &lt; 10.0"))
</pre>
</p><p>
Written with a variable as a threshold this becomes:
</p><p>
<pre>
layer.select(scales("shape.area &lt; thr"), { "thr" =&gt; 10.0 })
</pre>
</p><p>
This version modifies the input layer. A version that returns
a new layer with the selected shapes is <a href="#selected_if">selected_if</a>.
</p>
<a name="select_inside"/><h2>"select_inside" - Selects edges, edge pairs or polygons of self which are inside edges or polygons from the other layer</h2>
<keyword name="select_inside"/>
<p>Usage:</p>
@ -2960,6 +3139,15 @@ properties. See <a href="/about/drc_ref_drcsource.xml#input">DRCSource#input</a>
<a href="#map_props">map_props</a> is a way to change property keys and <a href="#remove_props">remove_props</a>
will entirely remove all user properties.
</p>
<a name="selected_if"/><h2>"selected_if" - Selects shapes based on the evaluation of an expression</h2>
<keyword name="selected_if"/>
<p>Usage:</p>
<ul>
<li><tt>layer.selected_if(expression [, variables])</tt></li>
</ul>
<p>
This method is the out-of-place version of <a href="#select_if">select_if</a>. It takes the same arguments.
</p>
<a name="sep"/><h2>"sep" - An alias for "separation"</h2>
<keyword name="sep"/>
<p>Usage:</p>
@ -3331,6 +3519,23 @@ one layer and all others in a second layer. This method is equivalent to calling
</p><p>
The options of this method are the same than <a href="#covering">covering</a>.
</p>
<a name="split_if"/><h2>"split_if" - Selects shapes based on the evaluation of an expression and returns selected and unselected shapes in different layers</h2>
<keyword name="split_if"/>
<p>Usage:</p>
<ul>
<li><tt>layer.selected_if(expression [, variables])</tt></li>
</ul>
<p>
This method, like the other 'split_...' methods returns two layers:
one with the result of <a href="#selected_if">selected_if</a>, and a second with all other shapes.
</p><p>
The following example splits a layer into two: one with the shapes that have an area
less than 10 square micrometers and another one with the shapes that have a bigger area:
</p><p>
<pre>
(smaller, bigger) = layer.split_if(scales("shape.area &lt; 10.0"))
</pre>
</p>
<a name="split_inside"/><h2>"split_inside" - Returns the results of <a href="#inside">inside</a> and <a href="#not_inside">not_inside</a> at the same time</h2>
<keyword name="split_inside"/>
<p>Usage:</p>

View File

@ -342,6 +342,82 @@ Specifying a factor of 2 will make all devices being extracted as if the
geometries were two times larger. This feature is useful when the drawn layout
does not correspond to the physical dimensions.
</p>
<a name="evaluate_nets"/><h2>"evaluate_nets" - Evaluates net properties and annotates shapes from a given layer on the nets</h2>
<keyword name="evaluate_nets"/>
<p>Usage:</p>
<ul>
<li><tt>evaluate_nets(primary_layer, secondary_layers, expression [, variables])</tt></li>
</ul>
<p>
The function takes a primary layer and a number of secondary layers, each of
them given a variable name.
It visits each net and evaluates the given expression on the net.
The expression needs to be written in KLayout expression notations.
</p><p>
The default action is to copy the shapes of the primary layer to the
output. This action can be modified in some ways: skip shapes of
certain nets or attach properties to the shapes during the evaluation.
</p><p>
Using the "put" function inside the expression, properties can be
attached to the output shapes. The properties can be computed using
a number of net attributes - area and perimeter for example.
</p><p>
Also the <class_doc href="Net">Net</class_doc> object representing the net is available through the
'net' function. This allows implementing a more elaborate
antenna check for example.
</p><p>
Also, the expression can choose to drop shapes and not copy them to
the output by calling the "skip" function with a "true" argument.
</p><p>
Arbitrary values can be passed as variables, which removes the need
to encode variable values into the expression. For this, use the
'variables' argument and pass a hash with names and values. Each of
those values becomes available as a variable with the given name
inside the expression.
</p><p>
The following functions are available inside the expressions:
</p><p>
<ul>
<li>"net" - the <class_doc href="Net">Net</class_doc> object of the current net </li>
<li>"skip(flag)" - if called with a 'true' argument, the primary layer's shapes are not copied for this net </li>
<li>"put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes </li>
<li>"area" - the combined area of the primary layer's shapes on the net in square micrometer units </li>
<li>"area(symbol)" - the combined area of the secondary layer's shapes on the net in square micrometer units </li>
<li>"perimeter" - the perimeter of the primary layer's shapes on the net in micrometer units </li>
<li>"perimeter(symbol)" - the perimeter of the secondary layer's shapes on the net in micrometer units </li>
</ul>
</p><p>
Here, 'symbol' is the name given to the secondary layer in the secondary layer
dictionary.
</p><p>
The following example emulates an antenna check. It computes the area ratio of metal vs. gate area and
attaches the value as a property with name 'AR' to the shapes, copied from the 'gate' layer:
</p><p>
<pre>
gate = ... # a layer with the gate shapes
metal = ... # a layer with metal shapes
# NOTE: 'MET' is the name we are going to use in the expression
antenna_errors = evaluate_nets(gate, { "MET" =&gt; metal }, "put('AR',area(MET)/area)")
</pre>
</p><p>
This other example also computes the area ratio of metal vs. gate area, and
outputs the gate shapes of all nets whose metal to gate area ratio is bigger than
500. The area ratio is output to a property with name 'AR':
</p><p>
<pre>
gate = ... # a layer with the gate shapes
metal = ... # a layer with metal shapes
variables = { "thr" =&gt; 500.0 }
expression = "var ar=area(MET)/area; put('AR',ar); skip(ar&lt;thr)"
antenna_errors = evaluate_nets(gate, { "MET" =&gt; metal }, expression, variables)
</pre>
</p><p>
NOTE: GDS does not support properties with string names, so
either save to OASIS, or use integer numbers for the property names.
</p>
<a name="extract_devices"/><h2>"extract_devices" - Extracts devices based on the given extractor class, name and device layer selection</h2>
<keyword name="extract_devices"/>
<p>Usage:</p>

View File

@ -5175,7 +5175,7 @@ CODE
# %DRC%
# @name evaluate
# @brief Evaluate expressions on the shapes of the layer
# @brief Evaluates expressions on the shapes of the layer
# @synopsis layer.evaluate(expression [, variables [, keep_properties ]])
#
# Evaluates the given expression on the shapes of the layer.
@ -5185,39 +5185,54 @@ CODE
# The expressions can place properties on the shapes using the
# "put" function. As input, the expressions will receive the
# (merged) shapes in micrometer units (e.g. RBA::DPolygon type)
# by calling the "shape" function. You can also call 'skip' with
# a 'true' value to drop the shape from the output entirely.
# by calling the "shape" function.
#
# By default, input shapes are copied to the output with the properties
# attached to them by "put". You can skip shapes by calling "skip" with
# a 'true' value. In that case, the shape is not copied. This allows
# implementing filters.
#
# Available functions are:
# Available functions for the expressions are:
#
# @ul
# @li "put(name, value)": creates a property with the given name and value @/li
# @li "skip(flag)": if called with a 'true' value, the shape will be dropped from the output @/li
# @li "shape": the current shape in micrometer units @/li
# @li "value(name)": the value of a property with name 'name' or nil if the current shape does not have a property with this name @/li
# @ul
# @/ul
#
# Properties with well-formed names (e.g. "VALUE") are available as
# variables in the expressions as a shortcut.
#
# 'variables' can be a hash of arbitrary names and values. Each of these values
# becomes available as variables in the expression. This eliminates the need
# to build expression strings to pass variable values.
# 'variables' is a hash of arbitrary names and values. Each of these values
# becomes available as a variable in the expression. This eliminates the need
# to build expression strings with pasted value strings for passing external values.
#
# If 'keep_properties' is true, the existing properties of the shape will be kept.
# Otherwise (the default), existing properties will be removed before adding new
# ones with 'put'.
#
# The following example computes the area of the shapes and puts them
# into a property 'area':
#
# @code
# layer.evaluate(scales("put('area', shape.area)"))
# @/code
#
# NOTE: GDS does not support properties with string names, so
# either save to OASIS or use integer numbers for the property names.
#
# The expressions require a hint
# whether the they make use of anisotropic or scale-dependent properties.
# whether they make use of anisotropic or scale-dependent properties.
# For example, the height of a box is an anisotropic property. If a check is made
# inside a rotated cell, the height transforms to a width and the check renders
# different results for the same cell if the cell is placed rotated and non-rotated.
# The solution is cell variant formation.
# different results for the same cell, if the cell is placed rotated and non-rotated.
# The solution is cell variant formation which happens automatically when the
# "aniso" hint is present.
#
# Similarly, if a check is made against physical dimensions, the check will have
# different results for cells placed with different magnifications. Such a check
# is not scale-invariant.
# is not scale-invariant and needs to get a "scaled" hint.
#
# By default it is assumed that the expressions are isotropic and scale invariant.
# You can mark an expression as anisotropic and/or scale dependent using the following
@ -5241,25 +5256,16 @@ CODE
# shape properties and fail to correctly produce the results in the presence
# of deep mode and rotated or magnified cell instances.
#
# The following example computes the area of the shapes and puts them
# into a property 'area':
#
# @code
# layer.evaluate(scales("put('area', shape.area)"))
# @/code
#
# NOTE: GDS does not support properties with string names, so
# either save to OASIS or use integer numbers for the property names.
#
# This version modifies the input layer. A version that returns
# a new layer is \evaluated.
# The "evaluate" method modifies the input layer. A version that returns
# a new layer without modifying the input is \evaluated.
# %DRC%
# @name evaluated
# @brief Evaluate expressions on the shapes of the layer and returns a new layer
# @brief Evaluates expressions on the shapes of the layer and returns a new layer
# @synopsis layer.evaluated(expression [, variables [, keep_properties]])
#
# This method is the out-of-place version of \evaluate.
# This method is the out-of-place version of \evaluate. It takes the same
# arguments.
def _make_proc(expression, variables, keep_properties)
@ -5324,21 +5330,22 @@ CODE
# @ul
# @li "shape": the current shape in micrometer units @/li
# @li "value(name)": the value of a property with name 'name' or nil if the current shape does not have a property with this name @/li
# @ul
# @/ul
#
# Properties with well-formed names (e.g. "VALUE") are available as
# variables in the expressions as a shortcut.
#
# The expressions require a hint
# whether the they make use of anisotropic or scale-dependent properties.
# whether they make use of anisotropic or scale-dependent properties.
# For example, the height of a box is an anisotropic property. If a check is made
# inside a rotated cell, the height transforms to a width and the check renders
# different results for the same cell if the cell is placed rotated and non-rotated.
# The solution is cell variant formation.
# different results for the same cell, if the cell is placed rotated and non-rotated.
# The solution is cell variant formation which happens automatically when the
# "aniso" hint is present.
#
# Similarly, if a check is made against physical dimensions, the check will have
# different results for cells placed with different magnifications. Such a check
# is not scale-invariant.
# is not scale-invariant and needs to get a "scaled" hint.
#
# By default it is assumed that the expressions are isotropic and scale invariant.
# You can mark an expression as anisotropic and/or scale dependent using the following
@ -5362,9 +5369,9 @@ CODE
# shape properties and fail to correctly produce the results in the presence
# of deep mode and rotated or magnified cell instances.
#
# 'variables' can be a hash of arbitrary names and values. Each of these values
# becomes available as variables in the expression. This eliminates the need
# to build expression strings to pass variable values.
# 'variables' is a hash of arbitrary names and values. Each of these values
# becomes available as a variable in the expression. This eliminates the need
# to build expression strings with pasted value strings for passing external values.
#
# The following example selects all shapes on the layer with an area
# less than 10 square micrometers:
@ -5373,6 +5380,12 @@ CODE
# layer.select(scales("shape.area < 10.0"))
# @/code
#
# Written with a variable as a threshold this becomes:
#
# @code
# layer.select(scales("shape.area < thr"), { "thr" => 10.0 })
# @/code
#
# This version modifies the input layer. A version that returns
# a new layer with the selected shapes is \selected_if.
@ -5381,7 +5394,7 @@ CODE
# @brief Selects shapes based on the evaluation of an expression
# @synopsis layer.selected_if(expression [, variables])
#
# This method is the out-of-place version of \select_if.
# This method is the out-of-place version of \select_if. It takes the same arguments.
# %DRC%
# @name split_if
@ -5389,10 +5402,10 @@ CODE
# @synopsis layer.selected_if(expression [, variables])
#
# This method, like the other 'split_...' methods returns two layers:
# one with the result of \\selected_if, and a second with all other shapes.
# one with the result of \selected_if, and a second with all other shapes.
#
# The following example splits a layer into two: one with the shapes with an area
# less than 10 square micrometers and one with the shapes with a bigger area:
# The following example splits a layer into two: one with the shapes that have an area
# less than 10 square micrometers and another one with the shapes that have a bigger area:
#
# @code
# (smaller, bigger) = layer.split_if(scales("shape.area < 10.0"))

View File

@ -779,38 +779,44 @@ module DRC
# It visits each net and evaluates the given expression on the net.
# The expression needs to be written in KLayout expression notations.
#
# By default, the shapes of the primary layer are copied to the output.
# The default action is to copy the shapes of the primary layer to the
# output. This action can be modified in some ways: skip shapes of
# certain nets or attach properties to the shapes during the evaluation.
#
# Using the "put" function inside the expression, properties can be
# attached to the output shapes. The properties can be computed using
# a number of net attributes - area and perimeter, but also the RBA::Net
# object representing the net. This allows implementing a more elaborate
# a number of net attributes - area and perimeter for example.
#
# Also the RBA::Net object representing the net is available through the
# 'net' function. This allows implementing a more elaborate
# antenna check for example.
#
# Also, the expression can choose to drop shapes and not copy then to
# Also, the expression can choose to drop shapes and not copy them to
# the output by calling the "skip" function with a "true" argument.
#
# Arbitrary values can be passed as variables, which removes the need
# to encode variable values into the expression.
# to encode variable values into the expression. For this, use the
# 'variables' argument and pass a hash with names and values. Each of
# those values becomes available as a variable with the given name
# inside the expression.
#
# The following functions are available
# The following functions are available inside the expressions:
#
# @ul
# @li "net" - the RBA::Net object of the current net
# @li "skip(flag)" - if called with a 'true' argument, the primary layer's shapes are not copied for this net
# @li "put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes
# @li "area" - the combined area of the primary layer's shapes on the net in square micrometer units
# @li "area(symbol)" - the combined area of the secondary layer's shapes on the net in square micrometer units
# @li "perimeter" - the perimeter of the primary layer's shapes on the net in micrometer units
# @li "perimeter(symbol)" - the perimeter of the secondary layer's shapes on the net in micrometer units
# @li "net" - the RBA::Net object of the current net @/li
# @li "skip(flag)" - if called with a 'true' argument, the primary layer's shapes are not copied for this net @/li
# @li "put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes @/li
# @li "area" - the combined area of the primary layer's shapes on the net in square micrometer units @/li
# @li "area(symbol)" - the combined area of the secondary layer's shapes on the net in square micrometer units @/li
# @li "perimeter" - the perimeter of the primary layer's shapes on the net in micrometer units @/li
# @li "perimeter(symbol)" - the perimeter of the secondary layer's shapes on the net in micrometer units @/li
# @/ul
#
# Here, 'symbol' is the name given to the secondary layer in the secondary layer
# dictionary.
#
# The following example computes the area ratio of metal vs. gate area and
# attaches the value on a property with name 'AR' to the shapes of a copy of the
# 'gate' layer:
# The following example emulates an antenna check. It computes the area ratio of metal vs. gate area and
# attaches the value as a property with name 'AR' to the shapes, copied from the 'gate' layer:
#
# @code
# gate = ... # a layer with the gate shapes
@ -820,7 +826,7 @@ module DRC
# antenna_errors = evaluate_nets(gate, { "MET" => metal }, "put('AR',area(MET)/area)")
# @/code
#
# The following example computes the area ratio of metal vs. gate area and
# This other example also computes the area ratio of metal vs. gate area, and
# outputs the gate shapes of all nets whose metal to gate area ratio is bigger than
# 500. The area ratio is output to a property with name 'AR':
#
@ -835,7 +841,7 @@ module DRC
# @/code
#
# NOTE: GDS does not support properties with string names, so
# either save to OASIS or use integer numbers for the property names.
# either save to OASIS, or use integer numbers for the property names.
def evaluate_nets(primary, secondary, expression, variables = {})