Klayout gds to dxf conversion problem

Hello everyone:
When I convert a client's gds file to dxf, an error message appears: "Top-level cell is not unique - DXF can only store a single top cell"
Is there a way to use the klayout script to automatically detect the top cell? And merge multiple top cells into one?
Hope to get your help

Comments

  • edited May 2024

    Hi,

    Automatically detecting the multi-top cells is easy.
    But I do not understand what you mean by merge multiple top cells into one.
    At least, it should be very risky because merging can easily destroy the designer's intentions.
    A designer (providing a GDS file) should specify which cell should be treated as the top cell if the GDS file contains multiple top cell candidates.

    I have prepared three GDS files using KLayout's test data set.

    image Image 2
    Image 3 Image 4

    To be continued.

  • edited May 2024

    Cont.

    The attached Python script f2514.py has the following options.

    ---------------------------------------------------------------------------------
     f2514.py
       To check the number of top cells in given GDS/OASIS file(s)
    
       option & argument : comment on option if any               | default value
       -----------------------------------------------------------+----------------
       <-i|--input<file>>: GDS/OASIS file(s) to test              | ''
           can be a pattern like '*.gds' (Linux); *.gds (Windows) |
       [-o|--gendxf]: generate corresponding DXF file(s)          | disabled
       [-?|--?]: print this usage and exit                        | disabled
    --------------------------------------------------------------+------------------
    

    $ ./f2514.py -i '*.gds'
    Input GDS <res_combine.gds> has a single (1) top cell:
        --> Res2
    
    Input GDS <ringo.gds> has a single (1) top cell:
        --> RINGO
    
    Input GDS <ringo_and_res_combined.gds> has (2) top cells:
        --> Res2
        --> RINGO
      !!! Consider unifying the top cells to eliminate ambiguity!!!
    

    With the -o option, it can generate the DXF files.
    If there are multiple top cells, DXF files will be top-cell-wise.

    $ ./f2514.py -i '*.gds' -o
    
    Input GDS <res_combine.gds> has a single (1) top cell:
        --> Res2
    
      >>> With top cell [Res2], generated <res_combine.dxf>
    
    Input GDS <ringo.gds> has a single (1) top cell:
        --> RINGO
    
      >>> With top cell [RINGO], generated <ringo.dxf>
    
    Input GDS <ringo_and_res_combined.gds> has (2) top cells:
        --> Res2
        --> RINGO
      !!! Consider unifying the top cells to eliminate ambiguity!!!
      >>> With top cell [Res2], generated <__Res2__ringo_and_res_combined.dxf>
      >>> With top cell [RINGO], generated <__RINGO__ringo_and_res_combined.dxf>
    

    To be continued.

  • edited May 2024

    Cont.

    Generated DXF files are attached here.
    I have confirmed that the script f2514.py can run on Linux, Windows 10, and Mac.

    Kazzz-S

  • Hi sekigawa:
    Thank you very much for your reply. My requirement is to convert each top cell in the gds file into a dxf file. I don't want to run the klayout gui interface. I want to achieve this function through the command line under Windows. Because I am a newbie to klayout, I will study the f2514.py file carefully and report any progress immediately.

    In addition, I wrote a simple script, but why can't I get the passed parameters?

    import pya
    import sys
    
    # Enter your Python code here ..
    # 重定向输出到日志文件
    log_file = open("script_log.txt", "w")
    sys.stdout = log_file
    sys.stderr = log_file
    # 输出Python版本
    print(f"Python version: {sys.version}")
    
    # 打印传入的参数
    print("Arguments passed to script:")
    for i, arg in enumerate(sys.argv):
        print(f"Argument {i}: {arg}")
    
    layout = pya.Layout()
    top = layout.create_cell("TOP")
    l1 = layout.layer(1, 0)
    top.shapes(l1).insert(pya.Box(0, 0, 1000, 2000))
    
    layout.write("t.gds")
    
    # 关闭日志文件
    log_file.close()
    

    I really hope to get your guidance

  • edited May 2024

    Hi,

    (1) My requirement is to convert each top cell in the gds file into a dxf file.
    (2) I don't want to run the klayout gui interface. I want to achieve this function through the command line under Windows.

    OK. f2514.py already assumed these requirements. To run f2514.py in a terminal, you need to install:
    1. an ordinary Python3 (I'm using 3.11.x) ===> https://www.python.org/downloads/
    and
    2. The klayout Python Module ===> https://www.klayout.org/klayout-pypi/

    KLayout's GUI application is NOT required.

    After installing the Python 3.11.x, execute python3 -m pip install klayout for installing klayout-pypi.


    Because I am a newbie to klayout, I will study the f2514.py file carefully and report any progress immediately.

    Take your time :smiley: I believe https://www.klayout.org/klayout-pypi/ is a good starting point.

    Kazzz-S

  • Cont.

    In the second half, you try to execute the script by running the KLayout GUI application in batch mode. In fact, this is not required for your application, as I mentioned above.
    I found your script can run if the arguments "123 456" are not passed. Am I right?

    In such a use, the klayout executable is not behaving as a normal Python.
    To pass a variable to the script via the klayout executable, we must use a special option -rd <name>=<value>.

    The list below shows all the options for the klayout executable captured on Mac.

    MacBookPro2{sekigawa} wildwolfcj (1)% which klayout
    klayout: aliased to /Applications/klayout-std.app/Contents/MacOS/klayout
    
    MacBookPro2{sekigawa} wildwolfcj (2)% klayout -h
    klayout [<options>] [<file>] ..
    options
      -b                  Batch mode (same as -zz -nc -rx)
      -c <config file>    Use this configuration file
      -nc                 Don't use a configuration file (implies -t)
      -d <debug level>    Set debug level
      -e                  Editable mode (allow editing of files)
      -ne                 Readonly mode (editing of files is disabled)
      -gr <file name>     Record GUI test file
      -gp <file name>     Replay GUI test file
      -gb <line number>   Replay GUI test file up to (including) line
      -gx <millisec>      Replay rate for GUI test file
      -gi                 Incremental logs for GUI test file
      -i                  Disable undo buffering (less memory requirements)
      -ni                 Enable undo buffering (default, overrides previous -i option)
      -j <path>           Add the given path to the macro project paths
      -k <log file>       Write log to the given file plus stdout/stderr
      -l <lyp file>       Use layer properties file
      -lx                 With -l: add other layers as well
      -lf                 With -l: use the lyp file as it is (no expansion to multiple layouts)
      -m <database file>  Load RDB (report database) file (into previous layout view)
      -mn <database file> Load L2NDB (layout to netlist database) file (into previous layout view)
      -n <technology>     Technology to use for next layout(s) on command line
      -nn <tech file>     Technology file (.lyt) to use for next layout(s) on command line
      -p <plugin>         Load the plugin (can be used multiple times)
      -r <script>         Execute main script on startup (after having loaded files etc.)
      -rr <script>        Like -r, but does not exit after executing the script
      -rm <script>        Execute script on startup before loading files (can be used multiple times)
      -rd <name>=<value>  Specify script variable <=== !!!!!
      -rx                 Ignore all implicit macros (*.rbm, rbainit, *.lym)
      -s                  Load files into same view
      -t                  Don't update the configuration file on exit
      -nt                 Update the configuration file on exit (default, overrides previous -t option)
      -u <file name>      Restore session from given file
      -v                  Print program version and exit
      -wd <name>=<value>  Define a variable within expressions
      -x                  Synchronous drawing mode
      -y <package>        Package installation: install package(s) and exit - can be used more than once
                          ('package' is a name, an URL and optionally a version in round brackets)
      -yd                 With -y: include dependencies
      -z                  Non-GUI mode (hidden views)
      -zz                 Non-GUI mode (database only, implies -nc)
    

    If I pass the arguments, they are assumed to be files, like

    MacBookPro2{sekigawa} wildwolfcj (3)% klayout -b -r sample1.py 123 456
    ERROR: Unable to open file: /Users/sekigawa/xxx/wildwolfcj/123 (errno=2)
    

    Kazzz-S

  • Hi,

    The environment settings shown in the attached document (thanks to ChatGPT) are required to run a Python script on a Windows terminal.
    Just for your information.

    Kazzz-S

  • edited May 2024

    hi sekigawa:
    Thank you for your patience
    I have fully understood the content of f2514.py, which can realize my needs, but I now have two problems now

    1 I run on the Windows system, but I did not find Which Klayout, only klayout_app.exe klayout_vo_app.exe, I am looking at the command line to find by where klayout to find

    2 -RD = I have tested to pass the parameters in this way in the command line
    klayout_vo_app -b -r C: \ users \ rj_84 \ klayout \ pymacros \ new_folder \ new_python_macro_1.py rd 123 = 456
    But how to get this parameter in py?
    I hope to get your guidance, thank you again!

  • hi sekigawa:
    I tried to obtain the 123 parameters in PY code in PY code that failed to get the 123 parameters

    # Get the parameters passed through -RD
    app = pya.application.instance ()
    Print ("test-1")
    names = app.get_config_names ()
    #print (names)
    config = app.get_config ("-rd")
    #config = app.get_config ("-rd")
    #config = app.get_config ("123")
    
    Print (config)
    
    
    Print ("test1")
    # Print parameter
    Print ("Parameters passed with -rd:")
    for key, value in config.items ():
     Print (f "{key} = {value}")
    
  • edited May 2024

    Hi @wildwolfcj,

    1 I run on the Windows system, but I did not find Which Klayout, only klayout_app.exe klayout_vo_app.exe, I am looking at the command line to find by where klayout to find

    You need neither klayout_app.exe nor klayout_vo_app.exe as long as you use the KLayout Python Module ===> https://www.klayout.org/klayout-pypi/.
    It is a different product from the KLayout GUI application.

    If your application does not need to use the full KLayout's features, like in this case, using this module should suffice.

    However, we must use the KLayout GUI application to check the conversion data and results visually.

    Running the KLayout GUI application in batch mode (you are trying now) was a single solution before this Python module was provided.


    2 -RD = I have tested to pass the parameters in this way in the command line
    klayout_vo_app -b -R C: \ users \ rj_84 \ klayout \ pymacros \ new_folder \ new_python_macro_1.rd 123 = 456
    But how to get this parameter in py?

    Suppose you invoke like klayout_app.exe -b -r /path/to/your/script.py -rd param1=123 -rd param2=abc.
    Then, /path/to/your/script.py will internally have global string object param1 and param2.
    The object names are case-sensitive.
    Beware that since param1 is to be a number, you must type-cast it to an integer or float inside the script before use.


    The attached ZIP file contains a similar GDS2-->DXF converter I wrote many years ago.
    gds2dxf.py is the main command line I/F.
    kgds2dxf.py is the actual worker.
    The former invokes the latter as a subprocess.

    Compare this with f2514.py. Do you think which is leaner and more elegant?

    Again, I emphasize that you should use the KLayout Python Module for your application.
    Hope I could convince you.

    Kazzz-S

  • Dear @wildwolfcj,

    I agree with @sekigawa, for such applications, it is easier to use the Python module. Specifically as it installs with the major Python distributions on Windows, such as Anaconda.

    I'd like to add a few things:

    1. If you have multiple top cells, you can use Cell#write on each top cell to write that one to a specific file, like this (Python):
    ly = ... # some layout
    for c in ly.each_top_cell():
      c.write(c.name + ".gds")
    
    1. DXF has many flavors and KLayout's DXF writer is not very good. It produces DXF which is halfway useful, but you need to carefully configure it. Otherwise you may not see the expected results in other tools. The way to do it is this:
    opt = pya.SaveLayoutOptions()
    opt.dxf_polygon_mode = 1
    ...
    
    ly = ... # some layout
    for c in ly.each_top_cell():
      c.write(c.name + ".gds", opt)
    

    For the options see the "dxf_..." attributes here: https://www.klayout.de/doc-qt5/code/class_SaveLayoutOptions.html#k_1

    Regards,

    Matthias

  • hi Matthias and sekigawa:
    Thank you very much for your patient guidance. According to the above information, I have been able to successfully convert gds containing multiple topcells into different dxf files. I will study the KLayout Python Module method to convert in the future.

    Thanks again

  • hi Matthias and sekigawa:
    After gds successfully converted dxf, I went to get the unit of the dxf file, but the value I got was
    public enum DrawingUnits { // // 摘要: // Unitless. Unitless, // // 摘要: // Inches. Inches, // // 摘要: // Feet. Feet, // // 摘要: // Miles. Miles, // // 摘要: // Millimeters. Millimeters, // // 摘要: // Centimeters. Centimeters, // // 摘要: // Meters. Meters, // // 摘要: // Kilometers. Kilometers, // // 摘要: // Microinches. Microinches, // // 摘要: // Mils (a thousandth of an inch). Mils, // // 摘要: // Yards. Yards, // // 摘要: // Angstroms. Angstroms, // // 摘要: // Nanometers. Nanometers, // // 摘要: // Microns. Microns, // // 摘要: // Decimeters. Decimeters, // // 摘要: // Decameters Decameters, // // 摘要: // Hectometers. Hectometers, // // 摘要: // Gigameters. Gigameters, // // 摘要: // AstronomicalUnits. AstronomicalUnits, // // 摘要: // LightYears. LightYears, // // 摘要: // Parsecs. Parsecs, // // 摘要: // US Survey Feet USSurveyFeet, // // 摘要: // US Survey Inches USSurveyInches, // // 摘要: // US Survey Yards USSurveyYards, // // 摘要: // US Survey Miles USSurveyMiles } }
    Unitless, how to convert the units in gds to dxf?
    Hope to get your help

  • edited June 2024

    Hi,

    How did you get the above strings?

    Basically, a DXF file is unitless.

    The UNITS in the sample GDS2 files are:

    #------------------------------------------------------------------------------------
    # Regarding the "dump_gds2" tool,
    #  refer to: https://www.klayout.de/forum/discussion/comment/10551/#Comment_10551
    #------------------------------------------------------------------------------------
    
    $ dump_gds2 ringo.gds | more
    
    000000000   00 06 00 02              HEADER
    000000004   02 58                      600
    000000006   00 1c 01 02              BGNLIB
    000000010   07 e3 00 03 00 08 00 16    2019-03-08 22:50:09
    000000018 + 00 32 00 09
    000000022   07 e3 00 03 00 08 00 16    2019-03-08 22:50:09
    000000030 + 00 32 00 09
    000000034   00 08 02 06              LIBNAME
    000000038   4c 49 42 00                "LIB"
    000000042   00 14 03 05              UNITS   <===
    000000046   3e 41 89 37 4b c6 a7 f0    0.001 <===
    000000054   39 44 b8 2f a0 9b 5a 54    1e-09 <===
    000000062   00 1c 05 02              BGNSTR
    :
    :
    
    $ dump_gds2 ringo_and_res_combined.gds | more
    000000000   00 06 00 02              HEADER
    000000004   02 58                      600
    000000006   00 1c 01 02              BGNLIB
    000000010   07 e8 00 05 00 1e 00 09    2024-05-30 09:35:56
    000000018 + 00 23 00 38
    000000022   07 e8 00 05 00 1e 00 09    2024-05-30 09:35:56
    000000030 + 00 23 00 38
    000000034   00 08 02 06              LIBNAME
    000000038   4c 49 42 00                "LIB"
    000000042   00 14 03 05              UNITS   <===
    000000046   3e 41 89 37 4b c6 a7 f0    0.001 <===
    000000054   39 44 b8 2f a0 9b 5a 54    1e-09 <===
    000000062   00 1c 05 02              BGNSTR
    :
    :
    
    $ dump_gds2 res_combine.gds | more
    000000000   00 06 00 02              HEADER
    000000004   00 05                      5
    000000006   00 1c 01 02              BGNLIB
    000000010   00 79 00 07 00 16 00 17    0121-07-22 23:12:53
    000000018 + 00 0c 00 35
    000000022   00 79 00 07 00 16 00 17    0121-07-22 23:14:35
    000000030 + 00 0e 00 23
    000000034   00 0c 02 06              LIBNAME
    000000038   41 44 45 5f 78 66 61 62    "ADE_xfab"
    000000046   00 14 03 05              UNITS   <===
    000000050   3e 41 89 37 4b c6 a7 f0    0.001 <===
    000000058   39 44 b8 2f a0 9b 5a 54    1e-09 <===
    000000066   00 1c 05 02              BGNSTR
    :
    :
    

    To be continues.

  • edited June 2024

    Cont.

    If you assume DXF's coordinate is in [mm], you must provide some more parameters to the SaveLayoutOptions object like:

    :
      so = db.SaveLayoutOptions()
      so.format       = "DXF"
      so.dbu          = 0.001 # [um]
      so.scale_factor = 0.001 # to assume DXF's coordinate is in [mm]
      layout.write( dxf, so )
    : 
    

    The attached f2415b.zip contains f2415b.py, a modified version of f2415.py.
    It also contains (1) ringo.dxf and (2)ringo_units.dxf.
    (1) was generated by f2415b.py. Then, I generated (2) from (1) by manually inserting $INSUNITS (see above ChatGPT's instruction).

    Both Autodesk DWG Trueview and QCad Professional view the two DXF files.

    Kazzz-S

  • Cont.

    Suppose f2514.py converted ringo.gds to ringo-A.dxf; similarly f2514b.py to ringo-B.dxf.
    As seen in the images below, the coordinate values in the former DXF are 1000 times as large as the latter.

    However, if the coordinate unit in the former is assumed to be [micron] and the latter be [mm], both designs are identical.



    Kazzz-S

  • Hi sekigawa:
    Thank you very much for your patient reply, it helps me a lot, thank you again

  • Very good, thanks @sekigawa for clarifying this :)

    I understand that DXF has views to provide dimensional drawings, but my knowledge is very limited here. I want to look into EazyDXF (https://pypi.org/project/ezdxf/) to see how they are embedding views, but I did not have time for this yet.

    Matthias

Sign In or Register to comment.