forked from huangqiangsheng/Ruby_mask
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMyLib.lym
297 lines (243 loc) · 10.1 KB
/
MyLib.lym
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category/>
<prolog/>
<epilog/>
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
<menu-path/>
<interpreter>ruby</interpreter>
<dsl-interpreter-name/>
<text># Sample PCell
#
# This sample PCell implements a library called "MyLib" with a single PCell that
# draws a circle. It demonstrates the basic implementation techniques for a PCell
# and how to use the "guiding shape" feature to implement a handle for the circle
# radius.
#
# NOTE: after changing the code, the macro needs to be rerun to install the new
# implementation. The macro is also set to "auto run" to install the PCell
# when KLayout is run.
module MyLib
include RBA
# Remove any definition of our classes (this helps when
# reexecuting this code after a change has been applied)
MyLib.constants.member?(:Circle) && remove_const(:Circle)
MyLib.constants.member?(:Taper) && remove_const(:Taper)
MyLib.constants.member?(:Mmi) && remove_const(:Mmi)
MyLib.constants.member?(:MyLib) && remove_const(:MyLib)
# The library where we will put the PCell into
class MyLib < Library
def initialize
# Set the description
self.description = "My First Library"
# Create the PCell declarations
layout.register_pcell("Circle", Circle::new)
layout.register_pcell("Taper", Taper::new)
layout.register_pcell("Mmi", Mmi::new)
# That would be the place to put in more PCells ...
# Register us with the name "MyLib".
# If a library with that name already existed, it will be replaced then.
register("MyLib")
end
end
# The PCell declaration for the circle
class Circle < PCellDeclarationHelper
include RBA
def initialize
# Important: initialize the super class
super
# declare the parameters
param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
param(:s, TypeShape, "", :default => DPoint::new(0, 0))
param(:r, TypeDouble, "Radius", :default => 0.1)
param(:n, TypeInt, "Number of points", :default => 64)
# this hidden parameter is used to determine whether the radius has changed
# or the "s" handle has been moved
param(:ru, TypeDouble, "Radius", :default => 0.0, :hidden => true)
end
def display_text_impl
# Provide a descriptive text for the cell
"Circle(L=#{l.to_s},R=#{'%.3f' % r.to_f})"
end
def coerce_parameters_impl
# We employ coerce_parameters_impl to decide whether the handle or the
# numeric parameter has changed (by comparing against the effective
# radius ru) and set ru to the effective radius. We also update the
# numerical value or the shape, depending on which on has not changed.
rs = nil
if s.is_a?(DPoint)
# compute distance in micron
rs = s.distance(DPoint::new(0, 0))
end
if rs && (r-ru).abs < 1e-6
set_ru rs
set_r rs
else
set_ru r
set_s DPoint::new(-r, 0)
end
# n must be larger or equal than 4
n > 4 || (set_n 4)
end
def can_create_from_shape_impl
# Implement the "Create PCell from shape" protocol: we can use any shape which
# has a finite bounding box
shape.is_box? || shape.is_polygon? || shape.is_path?
end
def parameters_from_shape_impl
# Implement the "Create PCell from shape" protocol: we set r and l from the shape's
# bounding box width and layer
set_r shape.bbox.width * layout.dbu / 2
set_l layout.get_info(layer)
end
def transformation_from_shape_impl
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
# bounding box to determine the transformation
Trans.new(shape.bbox.center)
end
def produce_impl
# This is the main part of the implementation: create the layout
# fetch the parameters
ru_dbu = ru / layout.dbu
# compute the circle
pts = []
da = Math::PI * 2 / n
n.times do |i|
pts.push(Point.from_dpoint(DPoint.new(ru_dbu * Math::cos(i * da), ru_dbu * Math::sin(i * da))))
end
# create the shape
cell.shapes(l_layer).insert(Polygon.new(pts))
end
end
# The PCell declaration for the circle
class Taper < PCellDeclarationHelper
include RBA
def initialize
# Important: initialize the super class
super
# declare the parameters
param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
param(:len, TypeDouble, "Length", :default => 5.0)
param(:width_in, TypeDouble, "Width_in", :default => 1.0)
param(:width_out, TypeDouble, "Width_out", :default => 2.0)
param(:eq, TypeString, "Equation", :default => 'x')
# this hidden parameter is used to determine whether the radius has changed
# or the "s" handle has been moved
end
def display_text_impl
# Provide a descriptive text for the cell
"Taper(L=#{len.to_s},w1=#{'%.3f' % width_in.to_f}, w2=#{'%.3f' % width_out.to_f}, eq = #{eq})"
end
def coerce_parameters_impl
end
def can_create_from_shape_impl
# Implement the "Create PCell from shape" protocol: we can use any shape which
# has a finite bounding box
shape.is_box? || shape.is_polygon? || shape.is_path?
end
def transformation_from_shape_impl
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
# bounding box to determine the transformation
Trans.new(shape.bbox.center)
end
def produce_impl
# This is the main part of the implementation: create the layout
pts = [DPoint.new(0,0), DPoint.new(len/layout.dbu,0)]
if 'x' == eq
pt1 = DPoint.new(0,width_in/layout.dbu/2.0)
pt2 = DPoint.new(Math.sqrt((pts[1]-pts[0]).sq_abs),width_out/layout.dbu/2.0)
pt3 = DPoint.new(Math.sqrt((pts[1]-pts[0]).sq_abs),-width_out/layout.dbu/2.0)
pt4 = DPoint.new(0,-width_in/layout.dbu/2.0)
polygon = RBA::DPolygon.new([pt1,pt2,pt3,pt4])
else
length = Math.sqrt((pts[1]-pts[0]).sq_abs)
element = Array((0..1).step(0.01))
pt1s = []
pt2s = []
element.each do |x|
width = width_in/layout.dbu + eval(eq)*(width_out-width_in)/layout.dbu
pt1s.push(RBA::DPoint.new(x*length,width/2.0))
pt2s.insert(0,RBA::DPoint.new(x*length,-width/2.0))
end
polygon = RBA::DPolygon.new(pt1s+pt2s)
end
cell.shapes(l_layer).insert(Polygon::from_dpoly(polygon))
end
end
class Mmi < PCellDeclarationHelper
include RBA
def initialize()
# Important: initialize the super class
super
# declare the parameters
param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
param(:l_wg, TypeDouble, "Waveguide_Length", :default => 2.0)
param(:width_in, TypeDouble, "Width_waveguide_in", :default => 1.0)
param(:width_out, TypeDouble, "Width_waveguide_out", :default => 1.5)
param(:eq, TypeString, "Equation", :default => 'x')
param(:l_mmi, TypeDouble, "MMI_Length", :default => 6.0)
param(:w_mmi, TypeDouble, "Width_MMI", :default => 6.0)
param(:gap, TypeDouble, "output waveguide gap", :default => 2.0)
# this hidden parameter is used to determine whether the radius has changed
# or the "s" handle has been moved
end
def display_text_impl
# Provide a descriptive text for the cell
"MMI(L=#{l_mmi.to_s},w_mmi=#{w_mmi.to_s}, w_wg=#{width_out.to_s})"
end
def coerce_parameters_impl
end
def can_create_from_shape_impl
# Implement the "Create PCell from shape" protocol: we can use any shape which
# has a finite bounding box
shape.is_box? || shape.is_polygon? || shape.is_path?
end
def transformation_from_shape_impl
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
# bounding box to determine the transformation
Trans.new(shape.bbox.center)
end
def produce_impl
# This is the main part of the implementation: create the layout
pts = [DPoint.new(0,0), DPoint.new(l_wg/layout.dbu,0)]
if 'x' == eq
pt1 = DPoint.new(0,width_in/layout.dbu/2.0)
pt2 = DPoint.new(Math.sqrt((pts[1]-pts[0]).sq_abs),width_out/layout.dbu/2.0)
pt3 = DPoint.new(Math.sqrt((pts[1]-pts[0]).sq_abs),-width_out/layout.dbu/2.0)
pt4 = DPoint.new(0,-width_in/layout.dbu/2.0)
polygon = DPolygon.new([pt1,pt2,pt3,pt4])
else
length = Math.sqrt((pts[1]-pts[0]).sq_abs)
element = Array((0..1).step(0.01))
pt1s = []
pt2s = []
element.each do |x|
width = width_in/layout.dbu + eval(eq)*(width_out-width_in)/layout.dbu
pt1s.push(DPoint.new(x*length,width/2.0))
pt2s.insert(0,DPoint.new(x*length,-width/2.0))
end
polygon = DPolygon.new(pt1s+pt2s)
end
cell.shapes(l_layer).insert(Polygon::from_dpoly(polygon))
t1 = DTrans::new(DTrans::M90)
t2 = DTrans::new(2*l_wg/layout.dbu+l_mmi/layout.dbu,gap/layout.dbu/2.0+width_out/layout.dbu/2.0)
cell.shapes(l_layer).insert(Polygon::from_dpoly(polygon.transformed(t1).transformed(t2)))
t2 = DTrans::new(2*l_wg/layout.dbu+l_mmi/layout.dbu,-gap/layout.dbu/2.0-width_out/layout.dbu/2.0)
cell.shapes(l_layer).insert(Polygon::from_dpoly(polygon.transformed(t1).transformed(t2)))
pts = [DPoint.new(l_wg/layout.dbu,-w_mmi/layout.dbu/2.0),DPoint.new(l_wg/layout.dbu,w_mmi/layout.dbu/2.0),
DPoint.new(l_wg/layout.dbu+l_mmi/layout.dbu,w_mmi/layout.dbu/2.0),DPoint.new(l_wg/layout.dbu+l_mmi/layout.dbu,-w_mmi/layout.dbu/2.0)]
cell.shapes(l_layer).insert(Polygon::from_dpoly(DPolygon.new(pts)))
end
end
# Instantiate and register the library
MyLib::new
end
</text>
</klayout-macro>