It looks like you're new here. If you want to get involved, click one of these buttons!
I am using MATLAB to generate a series of DXF files that I am importing into KLayout, converting each file to GDS, placing a TEXT PCell of the filename within the layout, then exporting the final GDS.
My problem is that I have generated many of these DXF files in the past and the dimensions in some cases are very small - around 20nm in diameter. When I use Ruby to script the above task, I cannot figure out a way to define the DBU of a newly-generated layout before importing the DXF file. As a result, there is snapping of the geometry to grid points.
This doesn't seem to be an issue if I import these files manually after changing the DXF reader options DBU to 0.0001, but I cannot figure out how to do it (if possible) with scripting. I have tried creating a blank layout and exporting with DBU = 0.0001, then reopening that blank layout and subsequently importing the DXF, but this does not solve the problem. I could solve this by going back to MATLAB and re-exporting the DXFs with scaled dimensions, then scaling back down using Ruby, but that would take a ton of care and time. I pasted my code below.
begin
include RBA
# INPUTS:
out_filepath ='E:'
opt = SaveLayoutOptions::new
opt.dbu = 0.0001
dbu = opt.dbu
um = opt.dbu*10000
opt.gds2_libname = "LIBNAME"
opt.format = "GDS2"
# Get relevant handles
app = Application.instance
mw = app.main_window
# Ask the user for the files
dialog = QFileDialog::new(mw)
dialog.setDirectory(QDir::homePath())
dialog.setFileMode(QFileDialog::ExistingFiles)
if (dialog.exec())
files = dialog.selectedFiles()
end
# Loop through each file and instantiate it under the parent cell
files.each_with_index { |f,i|
p "Reading #{f}"
ly = RBA::Layout::new()
ly.read(f)
top = ly.top_cell.name
# find the library that has the TEXT pcell
lib = RBA::Library.library_by_name("Basic")
lib || raise("Unknown lib 'Basic'")
# find the pcell named TEXT
pcell_decl = lib.layout.pcell_declaration("TEXT")
pcell_decl || raise("Unknown PCell 'TEXT'")
#gets the filename and shortens it to get rid of the directory, file extension, and the type of unit cell
filename = "#{f}"
strCut = filename.index('_')
filename = filename[strCut+1,filename.length-(strCut+1)-4]
filenameExt = filename + '.gds'
ly.write(File.expand_path(out_filepath + filenameExt), opt)
ly2 = RBA::Layout::new()
ly2.read(File.expand_path(out_filepath + filenameExt))
top2 = ly2.top_cell.name
# set some sample parameters (uses layer 0)
param = {
"text" => filename,
"layer" => RBA::LayerInfo::new(0, 0),
"mag" => 10
}
# build a param array using the param hash as a source
pv = pcell_decl.get_parameters.collect do |p|
param[p.name] || p.default
end
# create a PCell variant cell
pcell_var = ly2.add_pcell_variant(lib, pcell_decl.id, pv)
# instantiate that cell and move it to the top-center of the array
t = RBA::Trans::new(RBA::Trans::R0, 0, 0)
pcell_inst = ly2.cell(top2).insert(RBA::CellInstArray::new(pcell_var, t))
shiftX = -dbu*pcell_inst.bbox.width/2
shiftY = dbu*ly2.cell(top2).bbox.height/2
padding = 2*um
shiftY = shiftY+padding
trans = RBA::Trans::new(RBA::Trans::R0, shiftX, shiftY)
ly2.cell(top2).transform(pcell_inst,trans)
ly2.write(File.expand_path(out_filepath + filenameExt), opt)
}
end
Comments
IME the DBU comes from what your mask shop (or other lithography)
can deliver. I'm used to older nodes and 0.001um (1nm) has never
been close to a problem. But you might find that 20nm circles are a
little raggedy (ortho structures, less so).
Usually this choice would be nailed down before you get any or much
layout done. Here, seems like you'd have to go to "least common
denominator" if you want to assert a DBU that puts everything on grid.
An alternative might be searching for "off grid" and translating
vertices / PCell points to snap-to. But that might get messy, left
unattended.
You may have some manual work ahead of you. Might suggest returning
to the generating scripts and "bake in" gridding to that process, as a
"least incremental effort" approach (esp. if many objects come from
one script, that's leverage).
Hi eherrm,
The dbu can be modified thuough setting attribute of a Layout object
https://www.klayout.de/doc-qt5/code/class_Layout.html#method54
Hi dick_freebird, thanks for taking the time! Yes, 20nm circles are horribly drawn with the above code. I'm working with an electron beam lithography system with a spot size of 5nm, so those raggedy edges of small circles have an effect on the proximity-effect correction and the small circles end up not getting a high enough dosage. I can load these old DXF files manually into KLayout if I make sure to set the DXF reader options correctly, but doing this for all of these generated geometries would be a nightmare.
RawrRanger, thanks to you also for taking the time. Although your solution is one that I have tested and found doesn't work as we wanted, I took a deeper look into the link you provided and found the LoadLayoutOptions class. Turns out all I need to do is use this class to change the DXF reader options from within the script, then include these options in the initial DXF read() call. This is done in the same way the writer options are defined. The new lines of code are below. Thanks again!
Very good. That's exactly the way to solve this problem.
Please note that the database uses 32 bit integers unless you compile with the 64bit coordinate option. That limits the total available area to -2e9 ... 2e9 DBUs and with smaller DBU this area gets smaller too. In reality the usable range is smaller as differences also are represented in 32bit integers. So -1e9 to 1e9 DBUs is safe which still is 200x200mm in your case. But not enough to represent a 300mm wafer if you like to go in that direction.
Matthias