1############### 2Getting Started 3############### 4 5GDSII files contain a hierarchical representation of any polygonal geometry. 6They are mainly used in the microelectronics industry for the design of mask layouts, but are also employed in other areas. 7 8Because it is a hierarchical format, repeated structures, such as identical transistors, can be defined once and referenced multiple times in the layout, reducing the file size. 9 10There is one important limitation in the GDSII format: it only supports `weakly simple polygons <https://en.wikipedia.org/wiki/Simple_polygon>`_, that is, polygons whose segments are allowed to intersect, but not cross. 11 12In particular, curves and shapes with holes are *not* directly supported. 13Holes can be defined, nonetheless, by connecting their boundary to the boundary of the enclosing shape. 14In the case of curves, they must be approximated by a polygon. 15The number of points in the polygonal approximation can be increased to better approximate the original curve up to some acceptable error. 16 17The original GDSII format limits the number of vertices in a polygon to 199. 18This limit seems arbitrary, as the maximal number of vertices that can be stored in a GDSII record is 8190. 19Nonetheless, most modern software disregard both limits and allow an arbitrary number of points per polygon. 20Gdspy follows the modern version of GDSII, but this is an important issue to keep in mind if the generated file is to be used in older systems. 21 22The units used to represent shapes in the GDSII format are defined by the user. 23The default unit in gdspy is 1 µm (10⁻⁶ m), but that can be easily changed by the user. 24 25 26*********** 27First GDSII 28*********** 29 30Let's create our first GDSII file: 31 32.. code-block:: python 33 34 import gdspy 35 36 # The GDSII file is called a library, which contains multiple cells. 37 lib = gdspy.GdsLibrary() 38 39 # Geometry must be placed in cells. 40 cell = lib.new_cell('FIRST') 41 42 # Create the geometry (a single rectangle) and add it to the cell. 43 rect = gdspy.Rectangle((0, 0), (2, 1)) 44 cell.add(rect) 45 46 # Save the library in a file called 'first.gds'. 47 lib.write_gds('first.gds') 48 49 # Optionally, save an image of the cell as SVG. 50 cell.write_svg('first.svg') 51 52 # Display all cells using the internal viewer. 53 gdspy.LayoutViewer() 54 55 56After importing the `gdspy` module, we create a library `lib` to hold the design. 57Then a :class:`gdspy.Cell` is created and the rectangle is added to the cell. 58All shapes in the GDSII format exist inside cells. 59A cell can be imagined as a piece of paper where the layout will be defined. 60Later, the cells can be used to create a hierarchy of geometries, ass we'll see in :ref:`References`. 61 62Finally, the whole structure is saved in a file called "first.gds" in the current directory. 63By default, all created cells are included in this operation. 64 65The GDSII file can be opened in a number of viewers and editors, such as `KLayout <https://klayout.de/>`_. 66Alternatively, gdspy includes a simple viewer that can also be used: :class:`gdspy.LayoutViewer`. 67 68 69******** 70Polygons 71******** 72 73General polygons can be defined by an ordered list of vertices. 74The orientation of the vertices (clockwise/counter-clockwise) is not important. 75 76.. literalinclude:: makeimages.py 77 :language: python 78 :dedent: 4 79 :start-after: Polygons 80 :end-before: draw 81 82.. image:: _static/polygons.* 83 :align: center 84 85 86Holes 87===== 88 89As mentioned in :ref:`Getting Started`, holes have to be connected to the outer boundary of the polygon, as in the following example: 90 91.. literalinclude:: makeimages.py 92 :language: python 93 :dedent: 4 94 :start-after: Holes 95 :end-before: draw 96 97.. image:: _static/holes.* 98 :align: center 99 100 101Circles 102======= 103 104The :class:`gdspy.Round` class creates circles, ellipses, doughnuts, arcs and slices. 105In all cases, the arguments `tolerance` or `number_of_points` will control the number of vertices used to approximate the curved shapes. 106 107If the number of vertices in the polygon is larger than `max_points` (199 by default), it will be fractured in many smaller polygons with at most `max_points` vertices each. 108 109.. literalinclude:: makeimages.py 110 :language: python 111 :dedent: 4 112 :start-after: Circles 113 :end-before: draw 114 115.. image:: _static/circles.* 116 :align: center 117 118 119Curves 120====== 121 122Constructing complex polygons by manually listing all vertices in :class:`gdspy.Polygon` can be challenging. 123The class :class:`gdspy.Curve` can be used to facilitate the creation of polygons by drawing their shapes step-by-step. 124It uses a syntax similar to the `SVG path specification <https://www.w3.org/TR/SVG/paths.html>`_. 125 126A short summary of the available methods is presented below: 127 128====== ============================= 129Method Primitive 130====== ============================= 131L/l Line segments 132H/h Horizontal line segments 133V/v Vertical line segments 134C/c Cubic Bezier curve 135S/s Smooth cubic Bezier curve 136Q/q Quadratic Bezier curve 137T/t Smooth quadratic Bezier curve 138B/b General degree Bezier curve 139I/i Smooth interpolating curve 140arc Elliptical arc 141====== ============================= 142 143The uppercase version of the methods considers that all coordinates are absolute, whereas the lowercase considers that they are relative to the current end point of the curve. 144Except for :meth:`gdspy.Curve.I`, :meth:`gdspy.Curve.i` and :meth:`gdspy.Curve.arc`, they accept variable numbers of arguments that are used as coordinates to construct the primitive. 145 146.. literalinclude:: makeimages.py 147 :language: python 148 :dedent: 4 149 :start-after: Curves 150 :end-before: draw 151 152.. image:: _static/curves.* 153 :align: center 154 155Coordinate pairs can be given as a complex number: real and imaginary parts are used as x and y coordinates, respectively. 156That is useful to define points in polar coordinates. 157 158Elliptical arcs have syntax similar to :class:`gdspy.Round`, but they allow for an extra rotation of the major axis of the ellipse. 159 160.. literalinclude:: makeimages.py 161 :language: python 162 :dedent: 4 163 :start-after: Curves 1 164 :end-before: draw 165 166.. image:: _static/curves_1.* 167 :align: center 168 169Other curves can be constructed as cubic, quadratic and general-degree Bezier curves. 170Additionally, a smooth interpolating curve can be calculated with the methods :meth:`gdspy.Curve.I` and :meth:`gdspy.Curve.i`, which have a number of arguments to control the shape of the curve. 171 172.. literalinclude:: makeimages.py 173 :language: python 174 :dedent: 4 175 :start-after: Curves 2 176 :end-before: draw 177 178.. image:: _static/curves_2.* 179 :align: center 180 181 182Transformations 183=============== 184 185All polygons can be transformed trough :meth:`gdspy.PolygonSet.translate`, :meth:`gdspy.PolygonSet.rotate`, :meth:`gdspy.PolygonSet.scale`, and :meth:`gdspy.PolygonSet.mirror`. 186The transformations are applied in-place, i.e., no polygons are created. 187 188.. literalinclude:: makeimages.py 189 :language: python 190 :dedent: 4 191 :start-after: Transformations 192 :end-before: draw 193 194.. image:: _static/transformations.* 195 :align: center 196 197 198Layer and Datatype 199================== 200 201All shapes in the GDSII format are tagged with 2 properties: layer and datatype (or texttype in the case of :class:`gdspy.Label`). 202They are always 0 by default, but can be any integer in the range from 0 to 255. 203 204These properties have no predefined meaning. 205It is up to the system using the GDSII file to chose with to do with those tags. 206For example, in the CMOS fabrication process, each layer could represent a different lithography level. 207 208In the example below, a single file stores different fabrication masks in separate layer and datatype configurations. 209 210 211.. literalinclude:: makeimages.py 212 :language: python 213 :dedent: 4 214 :start-after: Layer and Datatype 215 :end-before: draw 216 217.. image:: _static/layer_and_datatype.* 218 :align: center 219 220 221********** 222References 223********** 224 225References give the GDSII format its hierarchical features. 226They work by reusing a cell content in another cell (without actually copying the whole geometry). 227As a simplistic example, imagine the we are designing a simple electronic circuit that uses hundreds of transistors, but they all have the same shape. 228We can draw the transistor just once and reference it throughout the circuit, rotating or mirroring each instance as necessary. 229 230Besides creating single references with :class:`gdspy.CellReference`, it is possible to create full 2D arrays with a single entity using :class:`gdspy.CellArray`. 231Both are exemplified below. 232 233.. literalinclude:: makeimages.py 234 :language: python 235 :dedent: 4 236 :start-after: References 237 :end-before: draw 238 239.. image:: _static/references.* 240 :align: center 241 242 243***** 244Paths 245***** 246 247Besides polygons, the GDSII format defines paths, witch are `polygonal chains <https://en.wikipedia.org/wiki/Polygonal_chain>`_ with associated width and end caps. 248The width is a single number, constant throughout the path, and the end caps can be flush, round, or extended by a custom distance. 249 250There is no specification for the joins between adjacent segments, so it is up to the system using the GDSII file to specify those. 251Usually the joins are straight extensions of the path boundaries up to some beveling limit. 252Gdspy also uses this specification for the joins. 253 254It is possible to circumvent all of the above limitations within gdspy by storing paths as polygons in the GDSII file. 255The disadvantage of this solution is that other software will not be able to edit the geometry as paths, since that information is lost. 256 257The construction of paths (either GDSII paths or polygonal paths) in gdspy is quite rich. 258There are 3 classes that can be used depending on the requirements of the desired path. 259 260 261Polygonal-Only Paths 262==================== 263 264The class :class:`gdspy.Path` is designed to allow the creation of path-like polygons in a piece-wise manner. 265It is the most computationally efficient class between the three because it *does not* calculate joins. 266That means the user is responsible for designing the joins. 267The paths can end up with discontinuities if care is not taken when creating them. 268 269.. literalinclude:: makeimages.py 270 :language: python 271 :dedent: 4 272 :start-after: Polygonal-Only Paths 273 :end-before: draw 274 275.. image:: _static/polygonal-only_paths.* 276 :align: center 277 278Just as with :ref:`Circles`, all curved geometry is approximated by line segments. 279The number of segments is similarly controlled by a `tolerance` or a `number_of_points` argument. 280Curves also include fracturing to limit the number of points in each polygon. 281 282More complex paths can be constructed with the methods :meth:`gdspy.Path.bezier`, :meth:`gdspy.Path.smooth`, and :meth:`gdspy.Path.parametric`. 283The example below demonstrates a couple of possibilities. 284 285.. literalinclude:: makeimages.py 286 :language: python 287 :dedent: 4 288 :start-after: Polygonal-Only Paths 1 289 :end-before: draw 290 291.. image:: _static/polygonal-only_paths_1.* 292 :align: center 293 294The width of the path does not have to be constant. 295Each path component can linearly taper the width of the path by using the `final_width` argument. 296In the case of a parametric curve, more complex width changes can be created by setting `final_width` to a function. 297 298Finally, parallel paths can be created simultaneously with the help of arguments `number_of_paths`, `distance`, and `final_distance`. 299 300.. literalinclude:: makeimages.py 301 :language: python 302 :dedent: 4 303 :start-after: Polygonal-Only Paths 2 304 :end-before: draw 305 306.. image:: _static/polygonal-only_paths_2.* 307 :align: center 308 309 310Flexible Paths 311============== 312 313Although very efficient, :class:`gdspy.Path` is limited in the type of path it can provide. 314For example, if we simply want a path going through a sequence of points, we need a class that can correctly compute the joins between segments. 315That's one of the advantages of class :class:`gdspy.FlexPath`. 316Other path construction methods are similar to those in :class:`gdspy.Path`. 317 318A few features of :class:`gdspy.FlexPath` are: 319 320- paths can be stored as proper GDSII paths; 321- end caps and joins can be specified by the user; 322- each parallel path can have a different width; 323- spacing between parallel paths is arbitrary; the user specifies the offset of each path individually. 324 325.. literalinclude:: makeimages.py 326 :language: python 327 :dedent: 4 328 :start-after: Flexible Paths 329 :end-before: draw 330 331.. image:: _static/flexible_paths.* 332 :align: center 333 334The following example shows other features, such as width tapering, arbitrary offsets, and custom joins and end caps. 335 336.. literalinclude:: makeimages.py 337 :language: python 338 :dedent: 4 339 :start-after: Flexible Paths 1 340 :end-before: draw 341 342.. image:: _static/flexible_paths_1.* 343 :align: center 344 345 346The corner type 'circular bend' (together with the `bend_radius` argument) can be used to automatically curve the path. 347This feature is used in :ref:`Example: Integrated Photonics`. 348 349.. literalinclude:: makeimages.py 350 :language: python 351 :dedent: 4 352 :start-after: Flexible Paths 2 353 :end-before: draw 354 355.. image:: _static/flexible_paths_2.* 356 :align: center 357 358 359Robust Paths 360============ 361 362In some situations, :class:`gdspy.FlexPath` is unable to properly calculate all the joins. 363This often happens when the width or offset of the path is relatively large with respect to the length of the segments being joined. 364Curves that join other curves or segments at sharp angles are an example of such situation. 365 366The class :class:`gdspy.RobustPath` can be used in such scenarios where robustness is more important than efficiency due to sharp corners or large offsets in the paths. 367The drawbacks of using :class:`gdspy.RobustPath` are the loss in computation efficiency (compared to the other 2 classes) and the impossibility of specifying corner shapes. 368The advantages are, as mentioned earlier, more robustness when generating the final geometry, and freedom to use custom functions to parameterize the widths or offsets of the paths in any construction method. 369 370.. literalinclude:: makeimages.py 371 :language: python 372 :dedent: 4 373 :start-after: Robust Paths 374 :end-before: draw 375 376.. image:: _static/robust_paths.* 377 :align: center 378 379Note that, analogously to :class:`gdspy.FlexPath`, :class:`gdspy.RobustPath` can be stored as a GDSII path as long as its width is kept constant. 380 381 382**** 383Text 384**** 385 386In the context of a GDSII file, text is supported in the form of labels, which are ASCII annotations placed somewhere in the geometry of a given cell. 387Similar to polygons, labels are tagged with layer and texttype values (texttype is the label equivalent of the polygon datatype). 388They are supported by the class :class:`gdspy.Label`. 389 390Additionally, gdspy offers the possibility of creating text as polygons to be included with the geometry. 391The class :class:`gdspy.Text` creates polygonal text that can be used in the same way as any other polygons in gdspy. 392The font used to render the characters contains only horizontal and vertical edges, which is important for some laser writing systems. 393 394.. literalinclude:: makeimages.py 395 :language: python 396 :dedent: 4 397 :start-after: # Text 398 :end-before: draw 399 400.. image:: _static/text.* 401 :align: center 402 403 404******************* 405Geometry Operations 406******************* 407 408Gdspy offers a number of functions and methods to modify existing geometry. 409The most useful operations include :func:`gdspy.boolean`, :func:`gdspy.slice`, :func:`gdspy.offset`, and :meth:`gdspy.PolygonSet.fillet`. 410 411 412Boolean Operations 413================== 414 415Boolean operations (:func:`gdspy.boolean`) can be performed on polygons, paths and whole cells. 416Four operations are defined: union ('or'), intersection ('and'), subtraction ('not'), and symmetric subtraction ('xor'). 417 418They can be computationally expensive, so it is usually advisable to avoid using boolean operations whenever possible. 419If they are necessary, keeping the number of vertices is all polygons as low as possible also helps. 420 421.. literalinclude:: makeimages.py 422 :language: python 423 :dedent: 4 424 :start-after: Boolean Operations 425 :end-before: draw 426 427.. image:: _static/boolean_operations.* 428 :align: center 429 430 431Slice Operation 432=============== 433 434As the name indicates, a slice operation subdivides a set of polygons along horizontal or vertical cut lines. 435 436In a few cases, a boolean operation can be substituted by one or more slice operations. 437Because :func:`gdspy.slice` is ususally much simpler than :func:`gdspy.boolean`, it is a good idea to use the former if possible. 438 439.. literalinclude:: makeimages.py 440 :language: python 441 :dedent: 4 442 :start-after: Slice Operation 443 :end-before: draw 444 445.. image:: _static/slice_operation.* 446 :align: center 447 448 449Offset Operation 450================ 451 452The function :func:`gdspy.offset` expands or contracts polygons by a fixed amount. 453It can operate on individual polygons or sets of them, in which case it may make sense to use the argument `join_first` to operate on the whole geometry as if a boolean 'or' was executed beforehand. 454 455.. literalinclude:: makeimages.py 456 :language: python 457 :dedent: 4 458 :start-after: Offset Operation 459 :end-before: draw 460 461.. image:: _static/offset_operation.* 462 :align: center 463 464 465Fillet Operation 466================ 467 468The method :meth:`gdspy.PolygonSet.fillet` can be used to round polygon corners. 469It doesn't have a `join_first` argument as :func:`gdspy.offset`, so if it will be used on a polygon, that polygon should probably not be fractured. 470 471.. literalinclude:: makeimages.py 472 :language: python 473 :dedent: 4 474 :start-after: Fillet Operation 475 :end-before: draw 476 477.. image:: _static/fillet_operation.* 478 :align: center 479 480 481************* 482GDSII Library 483************* 484 485All the information used to create a GDSII file is kept within an instance of :class:`GdsLibrary`. 486Besides all the geometric and hierarchical information, this class also holds a name and the units for all entities. 487The name can be any ASCII string. 488It is simply stored in the GDSII file and has no other purpose in gdspy. 489The units require some attention because they can impact the resolution of the polygons in the library when written to a file. 490 491Units in GDSII 492============== 493 494Two values are defined: `unit` and `precision`. 495The value of `unit` defines the unit size—in meters—for all entities in the library. 496For example, if ``unit = 1e-6`` (10⁻⁶ m, the default value), a vertex at (1, 2) should be interpreted as a vertex in real world position (1 × 10⁻⁶ m, 2 × 10⁻⁶ m). 497If `unit` changes to 0.001, then that same vertex would be located (in real world coordinates) at (0.001 m, 0.002 m), or (1 mm, 2 mm). 498 499The value of precision has to do with the type used to store coordinates in the GDSII file: signed 4-byte integers. 500Because of that, a finer coordinate grid than 1 `unit` is usually desired to define coordinates. 501That grid is defined, in meters, by `precision`, which defaults to ``1e-9`` (10⁻⁹ m). 502When the GDSII file is written, all vertices are snapped to the grid defined by `precision`. 503For example, for the default values of `unit` and `precision`, a vertex at (1.0512, 0.0001) represents real world coordinates (1.0512 × 10⁻⁶ m, 0.0001 × 10⁻⁶ m), or (1051.2 × 10⁻⁹ m, 0.1 × 10⁻⁹ m), which will be rounded to integers: (1051 × 10⁻⁹ m, 0 × 10⁻⁹ m), or (1.051 × 10⁻⁶ m, 0 × 10⁻⁶ m). 504The actual coordinate values written in the GDSII file will be the integers (1051, 0). 505By reducing the value of `precision` from 10⁻⁹ m to 10⁻¹² m, for example, the coordinates will have 3 additional decimal places of precision, so the stored values would be (1051200, 100). 506 507The downside of increasing the number of decimal places in the file is reducing the range of coordinates that can be stored (in real world units). 508That is because the range of coordinate values that can be written in the file are [-(2³²); 2³¹ - 1] = [-2,147,483,648; 2,147,483,647]. 509For the default `precsision`, this range is [-2.147483648 m; 2.147483647 m]. 510If `precision` is set to 10⁻¹² m, the same range is reduced by 1000 times: [-2.147483648 mm; 2.147483647 mm]. 511 512 513Saving a GDSII File 514=================== 515 516To save a GDSII file, simply use the :meth:`gdspy.GdsLibrary.write_gds` method, as in the :ref:`First GDSII`. 517 518An SVG image from a specific cell can also be exported through :meth:`gdspy.Cell.write_svg`, which was also demonstrated in :ref:`First GDSII`. 519 520 521Loading a GDSII File 522==================== 523 524To load an existing GDSII file (or to work simultaneously with multiple libraries), a new instance of :class:`GdsLibrary` can be created or an existing one can be used: 525 526.. code-block:: python 527 528 # Load a GDSII file into a new library 529 gdsii = gdspy.GdsLibrary(infile='filename.gds') 530 531 # Use a previously-created library to load the file contents into 532 existing_library.read_gds('filename.gds') 533 534In either case, care must be taken to merge the units from the library and the file, which is controlled by the argument `units` in :meth:`gdspy.GdsLibrary.read_gds` (keyword argument in :class:`gdspy.GdsLibrary`). 535 536Access to the cells in the loaded library is provided through the dictionary :attr:`gdspy.GdsLibrary.cell_dict` (cells indexed by name). 537The method :meth:`gdspy.GdsLibrary.top_level` can be used to find the top-level cells in the library (cells on the top of the hierarchy, i.e., cell that are not referenced by any other cells). 538 539 540******** 541Examples 542******** 543 544Integrated Photonics 545==================== 546 547This example demonstrates the use of gdspy primitives to create more complex structures. 548 549These structures are commonly used in the field of integrated photonics. 550 551:download:`photonics.py <_static/photonics.py>` 552 553:download:`photonics.gds <_static/photonics.gds>` 554 555.. literalinclude:: _static/photonics.py 556 :language: python 557 :linenos: 558 559Using System Fonts 560================== 561 562This example uses `matplotlib <https://matplotlib.org/>`_ to render text using any typeface present in the system. 563The glyph paths are then transformed into polygon arrays that can be used to create `gdspy.PolygonSet` objects. 564 565:download:`fonts.py <_static/fonts.py>` 566 567:download:`fonts.gds <_static/fonts.gds>` 568 569.. literalinclude:: _static/fonts.py 570 :language: python 571 :linenos: 572