optical pins name revised. Pin type added

This commit is contained in:
=
2026-06-07 22:56:33 +08:00
parent a4ac88f002
commit 8462c3397f
262 changed files with 3251 additions and 1134 deletions
+12 -4
View File
@@ -95,8 +95,12 @@ class PBS_3wg:
Att_D = nd.taper(length=5,width1=self.w2_tp,width2=self.w_wg,xs=self.xs).put(Att_D.pin['b0'])
Att_U = nd.taper(length=5,width1=self.w1_tp,width2=self.w_wg,xs=self.xs).put(Att_U.pin['b0'])
nd.Pin(name='a1',pin=Att_U.pin['b0']).put()
nd.Pin(name='a2',pin=Att_D.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=Att_U.pin['b0']).put()
nd.Pin(name='opt_a1',pin=Att_U.pin['b0'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',pin=Att_D.pin['b0']).put()
nd.Pin(name='opt_a2',pin=Att_D.pin['b0'],type="optical:").put()
nd.strt(length=w_crack,width=self.w_wg,xs=self.xs).put(Att_U.pin['b0'].x-w_crack/2,Att_U.pin['b0'].y,0)
nd.strt(length=w_crack,width=self.w_wg,xs=self.xs).put(Att_D.pin['b0'].x-w_crack/2,Att_D.pin['b0'].y,0)
@@ -111,8 +115,12 @@ class PBS_3wg:
Att_D = nd.taper(length=5,width1=self.w1_tp,width2=self.w_wg,xs=self.xs).put(Att_D.pin['b0'])
Att_U = nd.taper(length=5,width1=self.w2_tp,width2=self.w_wg,xs=self.xs).put(Att_U.pin['b0'])
nd.Pin(name='b1',pin=Att_U.pin['b0']).put()
nd.Pin(name='b2',pin=Att_D.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=Att_U.pin['b0']).put()
nd.Pin(name='opt_b1',pin=Att_U.pin['b0'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',pin=Att_D.pin['b0']).put()
nd.Pin(name='opt_b2',pin=Att_D.pin['b0'],type="optical:").put()
nd.strt(length=w_crack,width=self.w_wg,xs=self.xs).put(Att_U.pin['b0'].x-w_crack/2,Att_U.pin['b0'].y,0)
nd.strt(length=w_crack,width=self.w_wg,xs=self.xs).put(Att_D.pin['b0'].x-w_crack/2,Att_D.pin['b0'].y,0)
+45 -15
View File
@@ -116,15 +116,29 @@ class YBranch:
vtx = np.c_[vtx_x,vtx_y]
_my_polygon(layer_wg=layers,vtx=vtx).put(0,0,0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,self.w[-1]/2 - self.w_port/2,0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=1)
nd.Pin(name='b1',width=self.w_port).put(temp.pin['b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,self.w[-1]/2 - self.w_port/2,0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('opt_a1',self.L,self.w[-1]/2 - self.w_port/2,0)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=1)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('opt_a1',temp.pin['opt_b1'],flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_port).put(temp.pin['b1'])
nd.Pin(name='opt_b1',width=self.w_port,type="optical:").put(temp.pin['opt_b1'])
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,-self.w[-1]/2 + self.w_port/2,0,flip=1)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=0)
nd.Pin(name='b2',width=self.w_port).put(temp.pin['b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,-self.w[-1]/2 + self.w_port/2,0,flip=1)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('opt_a1',self.L,-self.w[-1]/2 + self.w_port/2,0,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('opt_a1',temp.pin['opt_b1'],flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',width=self.w_port).put(temp.pin['b1'])
nd.Pin(name='opt_b2',width=self.w_port,type="optical:").put(temp.pin['opt_b1'])
nd.Pin(name='a1',width=self.w[0]).put(0,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w[0]).put(0,0,180)
nd.Pin(name='opt_a1',width=self.w[0],type="optical:").put(0,0,180)
if (show_pins):
nd.put_stub()
@@ -227,7 +241,9 @@ class Ybranch_3wg:
self.L_in_tp = L_in_tp
self.cell = self.generate_gds(sharp_patch=sharp_patch)
self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
self.L = np.abs(self.cell.pin['opt_a1'].x - self.cell.pin['opt_b1'].x)
def generate_gds(self,sharp_patch,err_asy=0):
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
@@ -248,19 +264,25 @@ class Ybranch_3wg:
t_d = nd.taper(width2=w0,width1=w1,length=Lcp,xs=xs).put(0,-(w1/2+w0/2+gap),0)
t_in = nd.taper(width1=w_wg,width2=w0,length=L_in_tp,xs=xs).put(-L_in_tp,0,0)
t_in = nd.strt(width=w_wg,length=L_attach,xs=xs).put(t_in.pin['a0'],flip=0)
nd.Pin(name='a1',pin=t_in.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=t_in.pin['b0']).put()
nd.Pin(name='opt_a1',pin=t_in.pin['b0'],type="optical:").put()
au = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(t_u.pin['b0'],flip=0)
au = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(au.pin['b0'],flip=1)
au = nd.taper(width1=w0,width2=w_wg,length=L_in_tp,xs=xs).put(au.pin['b0'],flip=0)
au = nd.strt(width=w_wg,length=L_attach,xs=xs).put(au.pin['b0'],flip=0)
nd.Pin(name='b1',pin=au.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=au.pin['b0']).put()
nd.Pin(name='opt_b1',pin=au.pin['b0'],type="optical:").put()
ad = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(t_d.pin['b0'],flip=1)
ad = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(ad.pin['b0'],flip=0)
ad = nd.taper(width1=w0,width2=w_wg,length=L_in_tp,xs=xs).put(ad.pin['b0'],flip=0)
ad = nd.strt(width=w_wg,length=L_attach,xs=xs).put(ad.pin['b0'],flip=0)
nd.Pin(name='b2',pin=ad.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',pin=ad.pin['b0']).put()
nd.Pin(name='opt_b2',pin=ad.pin['b0'],type="optical:").put()
if (sharp_patch==True):
@@ -279,7 +301,9 @@ class Ybranch_3wg:
gc_cell = __cell_arg__(arg=gc,arg_name="gc",func_name="mxpic::Ybranch_3wg::generate_test_gds")
inst = self.cell.put('a1',-self.L/2,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: inst = self.cell.put('a1',-self.L/2,0,0)
inst = self.cell.put('opt_a1',-self.L/2,0,0)
gc_In = gc_cell.put('g1',-dX_gc2gc/2,0,180)
gc_O1 = gc_cell.put('g1',dX_gc2gc/2, dY_gc2gc/2,0)
@@ -287,10 +311,16 @@ class Ybranch_3wg:
pic_strip = Route(radius=Rbend,width=self.w_wg,xs=self.xs)
pic_strip.taper(pin=gc_O1.pin['g1'],width1=gc_O1.pin['g1'].width,width2=self.w_wg,length=5,arrow=False)
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b1'],arrow=False).put()
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['opt_b1'],arrow=False).put()
pic_strip.taper(pin=gc_O2.pin['g1'],width1=gc_O2.pin['g1'].width,width2=self.w_wg,length=5,arrow=False)
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b2'],arrow=False).put()
pic_strip.taper_p2p(pin1=gc_In.pin['g1'],pin2=inst.pin['a1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b2'],arrow=False).put()
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['opt_b2'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.taper_p2p(pin1=gc_In.pin['g1'],pin2=inst.pin['a1'],arrow=False).put()
pic_strip.taper_p2p(pin1=gc_In.pin['g1'],pin2=inst.pin['opt_a1'],arrow=False).put()
return C
+3 -1
View File
@@ -29,4 +29,6 @@ from .PBS import PBS_3wg
from .YBS import YBranch,Ybranch_3wg
from .racetrack import RacetrackResonator,Racetrack_MM_Adddrop,Racetrack_MM_Allpass,Racetrack_STD_Allpass
from .racetrack import RacetrackResonator,Racetrack_MM_Adddrop,Racetrack_MM_Allpass,Racetrack_STD_Allpass
from .edge_couplers import EC_dual_layer_px3
+12 -4
View File
@@ -134,8 +134,12 @@ class Bragg_apodized:
nd.strt(length=self.Period*(1-self.eta_etch),width=self.dT,xs=self.xs).put(_X_,_Y_,0)
nd.strt(length=self.Period*(1-self.eta_etch),width=self.dT,xs=self.xs).put(_X_+ds,-_Y_,0)
nd.Pin(name='a1',pin=INSTR.pin['a0'],width=self.w).put()
nd.Pin(name='b1',pin=INSTR.pin['b0'],width=self.w).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=INSTR.pin['a0'],width=self.w).put()
nd.Pin(name='opt_a1',pin=INSTR.pin['a0'],width=self.w,type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=INSTR.pin['b0'],width=self.w).put()
nd.Pin(name='opt_b1',pin=INSTR.pin['b0'],width=self.w,type="optical:").put()
if (self.show_pins):
nd.put_stub(pinsize=3)
return C
@@ -147,8 +151,12 @@ class Bragg_apodized:
L_brg = self.Period*self.N
INSTR = nd.strt(length=L_brg,width=self.w,xs=self.xs).put(0,0,0)
nd.Pin(name='a1',pin=INSTR.pin['a0'],width=self.w).put()
nd.Pin(name='b1',pin=INSTR.pin['b0'],width=self.w).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=INSTR.pin['a0'],width=self.w).put()
nd.Pin(name='opt_a1',pin=INSTR.pin['a0'],width=self.w,type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=INSTR.pin['b0'],width=self.w).put()
nd.Pin(name='opt_b1',pin=INSTR.pin['b0'],width=self.w,type="optical:").put()
for idx in range(0,self.N):
_X_ = idx*self.Period + (1-self.eta_etch)*self.Period
_Y_ = w_core/2 + self.dT/2
+204 -68
View File
@@ -167,8 +167,12 @@ class ring_bus_wg :
w=[self.w_bus,self.w_bus,self.w_trans,(self.w_trans+self.w_wg)/2,self.w_wg],xs=self.xs,
spiral_order=[1,self.clothoid_order,1,1],
sharp_patch=sharp_patch,end_patch=self.end_patch)
ar = cp.cell.put('a1',0,0,0).pin['b1']
al = cp.cell.put('a1',0,0,180,flip=1).pin['b1']
## revised in 2026.06.07 by Qin Yue
# legacy: ar = cp.cell.put('a1',0,0,0).pin['b1']
ar = cp.cell.put('opt_a1',0,0,0).pin['opt_b1']
## revised in 2026.06.07 by Qin Yue
# legacy: al = cp.cell.put('a1',0,0,180,flip=1).pin['b1']
al = cp.cell.put('opt_a1',0,0,180,flip=1).pin['opt_b1']
nd.strt(length=w_crack,width=self.w_bus,xs=self.xs).put(-w_crack/2,0,0)
nd.strt(length=w_crack,width=self.w_wg,xs=self.xs).put(ar.x-w_crack/2,ar.y,0)
@@ -183,8 +187,12 @@ class ring_bus_wg :
cp = circle(xs=self.xs,radius=self.R_cp, width = self.w_bus, theta_start = 270-self.dAc/2, theta_stop=270+self.dAc/2,res=self.res,
# n_points=self.n_points,
sharp_patch=sharp_patch).cell.put(0,self.R_cp,0)
al = cp.pin['a1']
ar = cp.pin['b1']
## revised in 2026.06.07 by Qin Yue
# legacy: al = cp.pin['a1']
al = cp.pin['opt_a1']
## revised in 2026.06.07 by Qin Yue
# legacy: ar = cp.pin['b1']
ar = cp.pin['opt_b1']
self.L = self.L + self.R_cp*self.dAc/180*np.pi
@@ -201,8 +209,12 @@ class ring_bus_wg :
Anti = circle(xs=self.xs,radius=self.R_max_anti, width = self.w_trans, theta_start = 90, theta_stop=90+self.A_anti,res=self.res,
# n_points=self.n_points,
sharp_patch=sharp_patch)
ar = Anti.cell.put('b1',TR.pin['b0']).pin['a1']
al = Anti.cell.put('b1',TL.pin['b0'],flip=1).pin['a1']
## revised in 2026.06.07 by Qin Yue
# legacy: ar = Anti.cell.put('b1',TR.pin['b0']).pin['a1']
ar = Anti.cell.put('opt_b1',TR.pin['b0']).pin['opt_a1']
## revised in 2026.06.07 by Qin Yue
# legacy: al = Anti.cell.put('b1',TL.pin['b0'],flip=1).pin['a1']
al = Anti.cell.put('opt_b1',TL.pin['b0'],flip=1).pin['opt_a1']
self.L = self.L + self.R_max_anti*self.A_anti*2*180/np.pi
@@ -221,8 +233,12 @@ class ring_bus_wg :
self.L = self.L + dL_patch*2
# self.dL_patch = dL_patch
nd.Pin(name='a1',pin=TPL.pin['b0'],width=self.w_wg).put()
nd.Pin(name='b1',pin=TPR.pin['b0'],width=self.w_wg).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=TPL.pin['b0'],width=self.w_wg).put()
nd.Pin(name='opt_a1',pin=TPL.pin['b0'],width=self.w_wg,type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=TPR.pin['b0'],width=self.w_wg).put()
nd.Pin(name='opt_b1',pin=TPR.pin['b0'],width=self.w_wg,type="optical:").put()
nd.strt(length=0.1,width=TPL.pin['b0'].width,xs=self.xs).put(TPL.pin['b0'].move(-0.05,0,0))
nd.strt(length=0.1,width=TPR.pin['b0'].width,xs=self.xs).put(TPR.pin['b0'].move(-0.05,0,0))
@@ -400,7 +416,9 @@ class ADC_STD_2x2:
self.tp_angle = tp_angle
self.sharp_patch = sharp_patch
self.cell = self.generate_gds(err=0,show_pins=show_pins)
self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
self.L = np.abs(self.cell.pin['opt_a1'].x - self.cell.pin['opt_b1'].x)
def generate_gds(self,err=0,show_pins=False):
@@ -445,7 +463,9 @@ class ADC_STD_2x2:
# attach_in = circle(angle=self.angle,radius=self.Rd0,width=self.wd0+err,xs=self.xs).cell.put('a1',0,vtx_lower_y[0]/2+vtx_lower_y[-1]/2,180,flip=0)
# attach_in = circle(angle=self.angle,radius=self.Rd0,width=self.wd0+err,xs=self.xs).cell.put('b1',attach_in.pin['b1'],flip=0)
pin_a2=nd.taper(width1=self.wd0+err,width2=self.wd_in,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
## revised in 2026.06.07 by Qin Yue
# legacy: pin_a2=nd.taper(width1=self.wd0+err,width2=self.wd_in,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
pin_a2=nd.taper(width1=self.wd0+err,width2=self.wd_in,length=Ltp,xs=self.xs).put(attach_in.pin['opt_b1']).pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_a2.width).put()
else :
@@ -455,7 +475,9 @@ class ADC_STD_2x2:
pin_a2 = nd.taper(xs=self.xs,length=Ltp,width1=self.wd0+err,width2=self.wd_in).put(temp.pin['b0']).pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_a2.width).put()
nd.Pin(name='a2',width=self.wd_in,pin=pin_a2).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',width=self.wd_in,pin=pin_a2).put()
nd.Pin(name='opt_a2',width=self.wd_in,pin=pin_a2,type="optical:").put()
if (self.Rd1!=0):
## placing the adiabatic bend attachment to lower waveguide, output port, label 1
@@ -476,7 +498,9 @@ class ADC_STD_2x2:
# attach_in = circle(angle=self.angle,radius=self.Rd1,width=self.wd1+err,xs=self.xs).cell.put('a1',self.Ld,vtx_lower_y[1]/2+vtx_lower_y[-2]/2,0,flip=1)
# attach_in = circle(angle=self.angle,radius=self.Rd1,width=self.wd1+err,xs=self.xs).cell.put('b1',attach_in.pin['b1'],flip=1)
pin_b2=nd.taper(width1=self.wd1+err,width2=self.wd_out,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
## revised in 2026.06.07 by Qin Yue
# legacy: pin_b2=nd.taper(width1=self.wd1+err,width2=self.wd_out,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
pin_b2=nd.taper(width1=self.wd1+err,width2=self.wd_out,length=Ltp,xs=self.xs).put(attach_in.pin['opt_b1']).pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_b2.width).put()
_dX_ = abs(pin_b2.x - self.Ld)
@@ -488,7 +512,9 @@ class ADC_STD_2x2:
pin_b2 = nd.taper(xs=self.xs,length=Ltp,width1=self.wd1+err,width2=self.wd_out).put().pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_b2.width).put()
nd.Pin(name='b2',width=self.wd_out,pin=pin_b2).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',width=self.wd_out,pin=pin_b2).put()
nd.Pin(name='opt_b2',width=self.wd_out,pin=pin_b2,type="optical:").put()
if (self.Ru0!=0):
@@ -511,7 +537,9 @@ class ADC_STD_2x2:
# attach_in = circle(angle=self.angle,radius=self.Ru0,width=self.wu0+err,xs=self.xs).cell.put('a1',0,vtx_upper_y[0]/2+vtx_upper_y[-1]/2,180,flip=1)
# attach_in = circle(angle=self.angle,radius=self.Ru0,width=self.wu0+err,xs=self.xs).cell.put('b1',attach_in.pin['b1'],flip=1)
pin_a1=nd.taper(width1=self.wu0+err,width2=self.wu_in,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
## revised in 2026.06.07 by Qin Yue
# legacy: pin_a1=nd.taper(width1=self.wu0+err,width2=self.wu_in,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
pin_a1=nd.taper(width1=self.wu0+err,width2=self.wu_in,length=Ltp,xs=self.xs).put(attach_in.pin['opt_b1']).pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_a1.width).put()
_dX_ = abs(pin_a1.x)
@@ -523,7 +551,9 @@ class ADC_STD_2x2:
pin_a1 = nd.taper(xs=self.xs,length=Ltp,width1=self.wu0+err,width2=self.wu_in).put().pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_a1.width).put()
nd.Pin(name='a1',width=self.wu_in,pin=pin_a1).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.wu_in,pin=pin_a1).put()
nd.Pin(name='opt_a1',width=self.wu_in,pin=pin_a1,type="optical:").put()
if (self.Ru1!=0):
if (self.sbend_type=='euler'):
@@ -546,7 +576,9 @@ class ADC_STD_2x2:
# attach_in = circle(angle=self.angle,radius=self.Ru1,width=self.wu1+err,xs=self.xs).cell.put('a1',self.Lu,vtx_upper_y[1]/2+vtx_upper_y[-2]/2,0,flip=0)
# attach_in = circle(angle=self.angle,radius=self.Ru1,width=self.wu1+err,xs=self.xs).cell.put('b1',attach_in.pin['b1'],flip=0)
pin_b1=nd.taper(width1=self.wu1+err,width2=self.wu_out,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
## revised in 2026.06.07 by Qin Yue
# legacy: pin_b1=nd.taper(width1=self.wu1+err,width2=self.wu_out,length=Ltp,xs=self.xs).put(attach_in.pin['b1']).pin['b0']
pin_b1=nd.taper(width1=self.wu1+err,width2=self.wu_out,length=Ltp,xs=self.xs).put(attach_in.pin['opt_b1']).pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_b1.width).put()
else :
Ltp = np.max([5,np.abs(self.wu1+err-self.wu_out)/np.tan(self.tp_angle/180*pi)])
@@ -555,7 +587,9 @@ class ADC_STD_2x2:
pin_b1 = nd.taper(xs=self.xs,length=Ltp,width1=self.wu1+err,width2=self.wu_out).put().pin['b0']
patch = nd.strt(xs=self.xs,length=0.01,width=pin_b1.width).put()
nd.Pin(name='b1',width=self.wu_out,pin=pin_b1).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.wu_out,pin=pin_b1).put()
nd.Pin(name='opt_b1',width=self.wu_out,pin=pin_b1,type="optical:").put()
dY1 = np.abs(pin_a1.y-pin_a2.y)
dX1 = np.abs(pin_a1.x-pin_a2.x)
@@ -576,10 +610,18 @@ class ADC_STD_2x2:
# nd.strt(length=L_patch,width=W_patch,layer=layers).put(np.min([pin_b1.x,pin_b2.x]),(pin_b1.y+self.wu_out/2-self.wd_out/2+pin_b2.y)/2,0)
if show_pins:
nd.put_stub(pinname='a1',pinsize=3)
nd.put_stub(pinname='a2',pinsize=3)
nd.put_stub(pinname='b1',pinsize=3)
nd.put_stub(pinname='b2',pinsize=3)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.put_stub(pinname='a1',pinsize=3)
nd.put_stub(pinname='opt_a1',pinsize=3)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.put_stub(pinname='a2',pinsize=3)
nd.put_stub(pinname='opt_a2',pinsize=3)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.put_stub(pinname='b1',pinsize=3)
nd.put_stub(pinname='opt_b1',pinsize=3)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.put_stub(pinname='b2',pinsize=3)
nd.put_stub(pinname='opt_b2',pinsize=3)
return C
@@ -597,24 +639,34 @@ class ADC_STD_2x2:
else :
raise Exception("ERROR: In <mxpic::passive::ADC_STD_2x2::generate_test_gds>, <gc> is not recongized as a cell")
inst = self.cell.put('a1',-self.L/2,self.cell.pin['a1'].y,0)
## revised in 2026.06.07 by Qin Yue
# legacy: inst = self.cell.put('a1',-self.L/2,self.cell.pin['a1'].y,0)
inst = self.cell.put('opt_a1',-self.L/2,self.cell.pin['opt_a1'].y,0)
pic_strip = Route(radius=15,width=self.wu_in,xs=self.xs)
GT_U_In = gc_cell.put('g1',-dX_gc2gc/2,dY_gc2gc/2,180)
nd.taper(width1=GT_U_In.pin['g1'].width,width2=self.wu_in,length=5,xs=self.xs).put(GT_U_In.pin['g1'])
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['a1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['a1']).put()
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['opt_a1']).put()
GT_D_In = gc_cell.put('g1',-dX_gc2gc/2,-dY_gc2gc/2,180)
nd.taper(width1=GT_D_In.pin['g1'].width,width2=self.wd_in,length=5,xs=self.xs).put(GT_D_In.pin['g1'])
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['a2'],width=self.wd_in).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['a2'],width=self.wd_in).put()
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['opt_a2'],width=self.wd_in).put()
GT_U_Out = gc_cell.put('g1', dX_gc2gc/2,dY_gc2gc/2,0)
nd.taper(width1=GT_U_Out.pin['g1'].width,width2=self.wu_out,length=5,xs=self.xs).put(GT_U_Out.pin['g1'])
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['b1'],width=self.wu_out).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['b1'],width=self.wu_out).put()
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['opt_b1'],width=self.wu_out).put()
GT_D_Out = gc_cell.put('g1', dX_gc2gc/2,-dY_gc2gc/2,0)
nd.taper(width1=GT_D_Out.pin['g1'].width,width2=self.wd_out,length=5,xs=self.xs).put(GT_D_Out.pin['g1'])
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['b2'],width=self.wd_out).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['b2'],width=self.wd_out).put()
pic_strip.sbend_p2p(original_function=not sharp_patch,pin2=inst.pin['opt_b2'],width=self.wd_out).put()
return C
@@ -707,28 +759,48 @@ class DC(ADC_STD_2x2):
gc_OU = gc_cell.put('g1',dX_gc2gc,-dY_gc2gc,0)
gc_OD = gc_cell.put('g1',dX_gc2gc,0,0)
# Put DC
inst = self.cell.put('a1',-self.L/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
## revised in 2026.06.07 by Qin Yue
# legacy: inst = self.cell.put('a1',-self.L/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
inst = self.cell.put('opt_a1',-self.L/2+dX_gc2gc/2,self.cell.pin['opt_a1'].y-dY_gc2gc/2,0)
# Connect all the ports
stripe=Route(radius=self.Ru0, width=self.wu_in, xs="strip")
if (abs(inst.pin['b1'].y - inst.pin['b2'].y)<10) :
temp = stripe.sbend_route(pin=inst.pin['a1'],offset=5).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: if (abs(inst.pin['b1'].y - inst.pin['b2'].y)<10) :
if (abs(inst.pin['opt_b1'].y - inst.pin['opt_b2'].y)<10) :
## revised in 2026.06.07 by Qin Yue
# legacy: temp = stripe.sbend_route(pin=inst.pin['a1'],offset=5).put(flip=1)
temp = stripe.sbend_route(pin=inst.pin['opt_a1'],offset=5).put(flip=1)
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=temp.pin['b0'],arrow=False,original_function=not sharp_patch).put()
temp = stripe.sbend_route(pin=inst.pin['a2'],offset=5).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = stripe.sbend_route(pin=inst.pin['a2'],offset=5).put()
temp = stripe.sbend_route(pin=inst.pin['opt_a2'],offset=5).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=temp.pin['b0'],arrow=False,original_function=not sharp_patch).put()
temp = stripe.sbend_route(pin=inst.pin['b1'],offset=5).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = stripe.sbend_route(pin=inst.pin['b1'],offset=5).put()
temp = stripe.sbend_route(pin=inst.pin['opt_b1'],offset=5).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=temp.pin['b0'],arrow=False,original_function=not sharp_patch).put()
temp = stripe.sbend_route(pin=inst.pin['b2'],offset=5).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = stripe.sbend_route(pin=inst.pin['b2'],offset=5).put(flip=1)
temp = stripe.sbend_route(pin=inst.pin['opt_b2'],offset=5).put(flip=1)
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=temp.pin['b0'],arrow=False,original_function=not sharp_patch).put()
else :
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['b2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['opt_a1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['opt_a2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['opt_b1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['b2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['opt_b2'],arrow=False,original_function=not sharp_patch).put()
return C
class BS_tdc(ADC_STD_2x2):
@@ -941,7 +1013,9 @@ class MDM(ADC_STD_2x2):
Rd0=R0,Rd1=R0,
angle=angle)
self.L = np.abs(self.cell.pin['a1'].x-self.cell.pin['b1'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: self.L = np.abs(self.cell.pin['a1'].x-self.cell.pin['b1'].x)
self.L = np.abs(self.cell.pin['opt_a1'].x-self.cell.pin['opt_b1'].x)
def generate_test_gds(self,gc,dX_gc2gc=300,dY_gc2gc=40,sharp_patch=True):
with nd.Cell(name=self.cell.cell_name+"_test", instantiate=False) as C:
@@ -949,10 +1023,16 @@ class MDM(ADC_STD_2x2):
gc_cell = __cell_arg__(arg=gc,arg_name="gc",func_name="mxpic::MDM::generate_test_gds")
# Put DC
L_taper = (np.abs(self.cell.pin['a1'].width-gc_cell.pin['g1'].width))/np.tan(2/180*pi)
## revised in 2026.06.07 by Qin Yue
# legacy: L_taper = (np.abs(self.cell.pin['a1'].width-gc_cell.pin['g1'].width))/np.tan(2/180*pi)
L_taper = (np.abs(self.cell.pin['opt_a1'].width-gc_cell.pin['g1'].width))/np.tan(2/180*pi)
mdm_In = self.cell.put('b1',-dX_gc2gc/2 + self.L + 25+L_taper,0,180)
mdm_Out = self.cell.put('b1', dX_gc2gc/2 - self.L - 25-L_taper,0,0,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: mdm_In = self.cell.put('b1',-dX_gc2gc/2 + self.L + 25+L_taper,0,180)
mdm_In = self.cell.put('opt_b1',-dX_gc2gc/2 + self.L + 25+L_taper,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: mdm_Out = self.cell.put('b1', dX_gc2gc/2 - self.L - 25-L_taper,0,0,flip=1)
mdm_Out = self.cell.put('opt_b1', dX_gc2gc/2 - self.L - 25-L_taper,0,0,flip=1)
GC_IU = gc_cell.put('g1',-dX_gc2gc/2,dY_gc2gc/2,180)
@@ -962,16 +1042,26 @@ class MDM(ADC_STD_2x2):
# # Connect all the ports
stripe=Route(radius=10, width=self.w_wg, xs="strip")
nd.taper(width1=mdm_In.pin['a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_In.pin['a1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(width1=mdm_In.pin['a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_In.pin['a1'])
nd.taper(width1=mdm_In.pin['opt_a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_In.pin['opt_a1'])
stripe.sbend_p2p(pin2=GC_IU.pin['g1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=GC_ID.pin['g1'],pin2=mdm_In.pin['a2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=GC_ID.pin['g1'],pin2=mdm_In.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=GC_ID.pin['g1'],pin2=mdm_In.pin['opt_a2'],arrow=False,original_function=not sharp_patch).put()
nd.taper(width1=mdm_Out.pin['a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_Out.pin['a1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(width1=mdm_Out.pin['a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_Out.pin['a1'])
nd.taper(width1=mdm_Out.pin['opt_a1'].width,width2=gc_cell.pin['g1'].width,length=L_taper,xs='strip').put(mdm_Out.pin['opt_a1'])
stripe.sbend_p2p(pin1=GC_OU.pin['g1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=GC_OD.pin['g1'],pin2=mdm_Out.pin['a2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=GC_OD.pin['g1'],pin2=mdm_Out.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=GC_OD.pin['g1'],pin2=mdm_Out.pin['opt_a2'],arrow=False,original_function=not sharp_patch).put()
stripe.taper_p2p(pin1=mdm_In.pin['b1'],pin2=mdm_Out.pin['b1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.taper_p2p(pin1=mdm_In.pin['b1'],pin2=mdm_Out.pin['b1'],arrow=False).put()
stripe.taper_p2p(pin1=mdm_In.pin['opt_b1'],pin2=mdm_Out.pin['opt_b1'],arrow=False).put()
return C
@@ -1095,10 +1185,18 @@ class DC_bend :
## Put pins
nd.Pin(name="a0", width=self.w_wg).put((port_in1.pin['b0'].x+port_in2.pin['b0'].x)/2, (port_in1.pin['b0'].y+port_in2.pin['b0'].y)/2, 180)
nd.Pin(name="a1", width=self.w_wg).put(port_in1.pin['b0'])
nd.Pin(name="a2", width=self.w_wg).put(port_in2.pin['b0'])
nd.Pin(name="b1", width=self.w_wg).put(port_out1.pin['b0'])
nd.Pin(name="b2", width=self.w_wg).put(port_out2.pin['b0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="a1", width=self.w_wg).put(port_in1.pin['b0'])
nd.Pin(name="opt_a1", width=self.w_wg,type="optical:").put(port_in1.pin['b0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="a2", width=self.w_wg).put(port_in2.pin['b0'])
nd.Pin(name="opt_a2", width=self.w_wg,type="optical:").put(port_in2.pin['b0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="b1", width=self.w_wg).put(port_out1.pin['b0'])
nd.Pin(name="opt_b1", width=self.w_wg,type="optical:").put(port_out1.pin['b0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="b2", width=self.w_wg).put(port_out2.pin['b0'])
nd.Pin(name="opt_b2", width=self.w_wg,type="optical:").put(port_out2.pin['b0'])
self.width = np.abs(port_out1.pin['b0'].y - port_out2.pin['b0'].y)
self.length = np.abs(port_out1.pin['b0'].x - port_in1.pin['b0'].x)
if self.show_pins:
@@ -1144,15 +1242,27 @@ class DC_bend :
gc_OU = gc_cell.put('g1',dX_gc2gc,-dY_gc2gc,0)
gc_OD = gc_cell.put('g1',dX_gc2gc,0,0)
# Put DC
dL_DC = self.cell.pin['b1'].x - self.cell.pin['a1'].x
inst = self.cell.put('a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
## revised in 2026.06.07 by Qin Yue
# legacy: dL_DC = self.cell.pin['b1'].x - self.cell.pin['a1'].x
dL_DC = self.cell.pin['opt_b1'].x - self.cell.pin['opt_a1'].x
## revised in 2026.06.07 by Qin Yue
# legacy: inst = self.cell.put('a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
inst = self.cell.put('opt_a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['opt_a1'].y-dY_gc2gc/2,0)
# Connect all the ports
stripe=Route(radius=10, width=self.w_wg, xs="strip")
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['b2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=inst.pin['opt_a1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=inst.pin['opt_a2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=inst.pin['opt_b1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['b2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=inst.pin['opt_b2'],arrow=False,original_function=not sharp_patch).put()
return C
@@ -1237,7 +1347,9 @@ class DC_pX_3sg:
self.cellU = cells[2]
self.cellD = cells[1]
self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
self.L = np.abs(self.cell.pin['opt_a1'].x - self.cell.pin['opt_b1'].x)
self.length = self.L
def generate_gds(self,err=0):
@@ -1261,7 +1373,9 @@ class DC_pX_3sg:
cp_u_r = nd.bend(radius=self.R0,angle=self.A,xs=self.xs_wg,width=w_cp).put(flip=0)
cp_u_r = nd.taper(width1=w_cp,width2=self.w_wg,xs=self.xs_wg,length=2).put()
nd.Pin(name='a1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width).put()
nd.Pin(name='opt_a1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width,type="optical:").put()
## middle segment phase shifter
if self.pX_type == "symmetric":
@@ -1280,7 +1394,9 @@ class DC_pX_3sg:
cp_u_r = nd.bend(radius=self.R0,angle=self.A,xs=self.xs_wg,width=w_cp).put(flip=1)
cp_u_r = nd.taper(width1=w_cp,width2=self.w_wg,xs=self.xs_wg,length=2).put()
nd.Pin(name='b1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width).put()
nd.Pin(name='opt_b1',pin=cp_u_r.pin['b0'],width=cp_u_r.pin['b0'].width,type="optical:").put()
nd.Pin(name='b0').put(cp_u.pin['b0'])
@@ -1299,7 +1415,9 @@ class DC_pX_3sg:
cp_d_r = nd.bend(radius=self.R0,angle=self.A,xs=self.xs_wg,width=w_cp).put()
# cp_d_r = nd.taper(width1=w_cp,width2=self.w_wg,xs=self.xs_wg,length=2).put()
nd.Pin(name='a2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width).put()
nd.Pin(name='opt_a2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width,type="optical:").put()
## middle segment phase shifter
if self.pX_type == "symmetric":
@@ -1323,7 +1441,9 @@ class DC_pX_3sg:
else:
cp_d_r = nd.bend(radius=self.R0,angle=self.A,xs=self.xs_wg,width=w_cp).put(flip=1)
nd.Pin(name='b2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width).put()
nd.Pin(name='opt_b2',pin=cp_d_r.pin['b0'],width=cp_d_r.pin['b0'].width,type="optical:").put()
nd.Pin(name='b0').put(cp_d.pin['b0'])
@@ -1331,8 +1451,12 @@ class DC_pX_3sg:
wgUp = CUP.put(0,(w_cp/2+gap/2),0)
wgDown = CDOWN.put(0,-(w_cp/2+gap/2),0)
wgUp.raise_pins(['a1','b1'],['a1','b1'])
wgDown.raise_pins(['a2','b2'],['a2','b2'])
## revised in 2026.06.07 by Qin Yue
# legacy: wgUp.raise_pins(['a1','b1'],['a1','b1'])
wgUp.raise_pins(['opt_a1','opt_b1'],['opt_a1','opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: wgDown.raise_pins(['a2','b2'],['a2','b2'])
wgDown.raise_pins(['opt_a2','opt_b2'],['opt_a2','opt_b2'])
nd.Pin(name='a0').put((self.Lc1+self.Lc2+self.Lp1+self.Lt*2)/2,0,180)
nd.Pin(name='b0').put((self.Lc1+self.Lc2+self.Lp1+self.Lt*2)/2,0,0)
@@ -1355,15 +1479,27 @@ class DC_pX_3sg:
gc_OU = gc_cell.put('g1',dX_gc2gc,-dY_gc2gc,0)
gc_OD = gc_cell.put('g1',dX_gc2gc,0,0)
# Put DC
dL_DC = self.cell.pin['b1'].x - self.cell.pin['a1'].x
## revised in 2026.06.07 by Qin Yue
# legacy: dL_DC = self.cell.pin['b1'].x - self.cell.pin['a1'].x
dL_DC = self.cell.pin['opt_b1'].x - self.cell.pin['opt_a1'].x
# inst = self.cell.put('a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
DC_pX3 = self.cell.put('a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
## revised in 2026.06.07 by Qin Yue
# legacy: DC_pX3 = self.cell.put('a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['a1'].y-dY_gc2gc/2,0)
DC_pX3 = self.cell.put('opt_a1',-dL_DC/2+dX_gc2gc/2,self.cell.pin['opt_a1'].y-dY_gc2gc/2,0)
# Connect all the ports
stripe=Route(radius=10, width=self.w_wg, xs="strip")
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=DC_pX3.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=DC_pX3.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=DC_pX3.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=DC_pX3.pin['b2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=DC_pX3.pin['a1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_IU.pin['g1'],pin2=DC_pX3.pin['opt_a1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=DC_pX3.pin['a2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_ID.pin['g1'],pin2=DC_pX3.pin['opt_a2'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=DC_pX3.pin['b1'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OD.pin['g1'],pin2=DC_pX3.pin['opt_b1'],arrow=False,original_function=not sharp_patch).put()
## revised in 2026.06.07 by Qin Yue
# legacy: stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=DC_pX3.pin['b2'],arrow=False,original_function=not sharp_patch).put()
stripe.sbend_p2p(pin1=gc_OU.pin['g1'],pin2=DC_pX3.pin['opt_b2'],arrow=False,original_function=not sharp_patch).put()
return C
+24 -8
View File
@@ -69,10 +69,18 @@ class Cross:
_my_polygon(layer_wg=layers,vtx=vtx).put(0,L_arm,-90)
_my_polygon(layer_wg=layers,vtx=vtx).put(L_arm,0,180)
nd.Pin(name='a1',width=self.w[0]).put(-L_arm,0,180)
nd.Pin(name='a2',width=self.w[0]).put( 0,-L_arm,-90)
nd.Pin(name='b2',width=self.w[0]).put( 0, L_arm, 90)
nd.Pin(name='b1',width=self.w[0]).put( L_arm,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w[0]).put(-L_arm,0,180)
nd.Pin(name='opt_a1',width=self.w[0],type="optical:").put(-L_arm,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',width=self.w[0]).put( 0,-L_arm,-90)
nd.Pin(name='opt_a2',width=self.w[0],type="optical:").put( 0,-L_arm,-90)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',width=self.w[0]).put( 0, L_arm, 90)
nd.Pin(name='opt_b2',width=self.w[0],type="optical:").put( 0, L_arm, 90)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w[0]).put( L_arm,0,0)
nd.Pin(name='opt_b1',width=self.w[0],type="optical:").put( L_arm,0,0)
if (show_pins):
nd.put_stub()
@@ -99,12 +107,20 @@ class Cross:
pin_pre = gc_In.pin['g1']
for _idx_ in range(0,num):
inst = self.cell.put('a0',_idx_*dX - (num/2 - 1/2)*dX)
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pin_pre = inst.pin['b1']
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['opt_a1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pin_pre = inst.pin['b1']
pin_pre = inst.pin['opt_b1']
nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['b2'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['b2'])
nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['opt_b2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['a2'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['a2'])
nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['opt_a2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
gc_Out = gc_cell.put('g1', dX_gc2gc/2,0,0)
@@ -0,0 +1,256 @@
import nazca as nd
import numpy as np
from ...geometry import _my_polygon
class EC_dual_layer_px3():
"""
Dual-layer Edge Coupler (Spot Size Converter) for fiber-to-chip coupling.
This component manages the adiabatic transition between a high-index
contrast core and a secondary slab/cladding layer (e.g., SiN to SOI).
Parameters
----------
name : str
Unique identifier for the device cell.
w_in : float
Input waveguide width in microns.
L_in : float
Length of the initial input section.
Ltp1, Ltp2, Ltp3 : float
Lengths of the first, second, and third taper sections respectively.
L_end : float, optional
Length of the final facet extension (default is 0).
w_tip_core : float, optional
Width of the core taper tip in microns (default is 0.2).
w1_slab : float, optional
Initial width of the slab/cladding layer.
w_tip_slab : float, optional
Width of the slab taper tip at the facet.
w_mid_slab : float, optional
Width of the slab at the transition midpoint.
w_box, w_box_end, L_box_end : float, optional
Dimensions for the deep-trench/oxide box clearing.
w_DT : float, optional
Deep Trench width.
xs_SiN : str, optional
Cross-section name for the Nitride layer (default is "sin").
layer_SiN_slab : str, optional
GDS layer name for the SiN slab.
layer_DT : str, optional
GDS layer for the deep trench/oxide facet.
xs_Trench : str, optional
Cross-section name for the air trench.
layer_top_cover : str, optional
GDS layer for the optical pad/top cladding opening.
layer_dum_exl_be : str, optional
Layer for dummy exclusion (BEOL).
angle_tile : float, optional
Facet tilt angle in degrees to reduce back-reflection (default is 8).
R_bend : float, optional
Radius of curvature for associated routing bends (default is 50).
"""
def __init__(self,
name: str = None,
w_in: float = 1.0,
L_in: float = 15,
Ltp1: float = 100,
Ltp2: float = 200,
Ltp3: float = 400,
L_end: float = 0,
w_tip_core: float = 0.2,
w1_slab: float = 0.6,
w_tip_slab: float = 0.2,
w_mid_slab: float = 0.45,
w_box: float = 8,
w_box_end: float = 12,
L_box_end: float = 2,
w_DT: float = 12,
xs_SiN: str = "sin",
layer_SiN_slab: str = "SiN_Rib_WG",
layer_DT: str = "OXIDE_FACET",
xs_Trench: str = "air_trench",
layer_top_cover: str = "PAD_OPTICAL",
layer_dum_exl_be:str=None,
angle_tile: float = 8,
R_bend: float = 50,
):
""""""
""" This is the instruction for building a sample """
self.name = name
if (self.name is None): self.instantiate = False
else: self.instantiate = True
self.w_in = w_in
self.L_in = L_in
self.Ltp1 = Ltp1
self.Ltp2 = Ltp2
self.Ltp3 = Ltp3
self.L_end = L_end
self.w_tip_core = w_tip_core
self.w1_slab = w1_slab
self.w_tip_slab = w_tip_slab
self.w_mid_slab = w_mid_slab
self.w_box = w_box
self.w_box_end = w_box_end
self.L_box_end = L_box_end
self.w_DT = w_DT
self.xs_SiN = xs_SiN
self.layer_SiN_slab = layer_SiN_slab
self.layer_top_cover = layer_top_cover
self.layer_dum_exl_be = layer_dum_exl_be
self.layer_DT = layer_DT
self.xs_Trench = xs_Trench
self.angle_tile = angle_tile
self.R_bend = R_bend
self.cell = self.generate_gds()
def generate_gds(self):
""" central core """
with nd.Cell(instantiate=False) as EC_core:
""" === 1.1 Building core waveguide === """
t0 = nd.strt(xs=self.xs_SiN,length=self.L_in,width=self.w_in).put(0,0,0)
t1 = nd.taper(xs=self.xs_SiN,length=self.Ltp1,width1=self.w_in,width2=self.w1_slab).put()
t2 = nd.taper(xs=self.xs_SiN,length=self.Ltp2,width1=self.w1_slab,width2=self.w_mid_slab).put()
t3 = nd.taper(xs=self.xs_SiN,length=self.Ltp3,width1=self.w_mid_slab,width2=self.w_tip_slab).put()
nd.Pin(name="b0").put(t3.pin['b0'].x+self.L_end,t3.pin['b0'].y,0)
port = nd.bend(radius=self.R_bend,width=self.w_in,angle=self.angle_tile,xs=self.xs_SiN).put(t0.pin['a0'],flip=1)
""" Adding dummy exclusions """
L_EC = self.Ltp1+self.Ltp2+self.Ltp3+self.L_end
nd.strt(layer = self.layer_dum_exl_be,width=75,length=self.L_in + L_EC).put(0,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: port.raise_pins(['b0','b0'],['a0','a1'])
port.raise_pins(['b0','b0'],['a0','opt_a1'])
## revised in 2026.06.07 by Qin Yue
EC_core.pin['opt_a1'].type = "optical:"
""" === 1.2 Building cladding waveguide === """
w_etch = 4
y_shift = (self.w_tip_core/2-self.w_in/2)
## etching of the 400 nm region
nd.taper(layer=self.layer_SiN_slab,width1=w_etch,width2=w_etch,shift=y_shift,
length=self.Ltp1).put(t1.pin['b0'].x,t1.pin['b0'].y+self.w_tip_core/2+w_etch/2,180)
nd.taper(layer=self.layer_SiN_slab,width1=w_etch,width2=w_etch/2,shift=0,
length=self.L_in).put()
nd.taper(layer=self.layer_SiN_slab,width1=w_etch,width2=w_etch,shift=y_shift,
length=self.Ltp1).put(t1.pin['b0'].x,t1.pin['b0'].y-self.w_tip_core/2-w_etch/2,180,flip=1)
nd.taper(layer=self.layer_SiN_slab,width1=w_etch,width2=w_etch/2,shift=0,
length=self.L_in).put()
## etching of the 200 nm region
nd.taper(layer=self.layer_SiN_slab,width1=self.w_tip_core+2*w_etch,width2=w_etch+self.w_tip_slab,
length=self.Ltp2+self.Ltp3+1).put(t1.pin['b0'])
## patch
nd.strt(layer=self.layer_SiN_slab,width=self.w_tip_core+2*w_etch,
length=0.1).put(t1.pin['b0'].move(-0.05,0,0))
""" Corener patch """
angle_arc = self.angle_tile/180*np.pi
""" === 1.3 Building Air trenches === """
for layers,growx,growy,acc in nd.layeriter(xs=self.xs_Trench):
(a1,b1), (a2,b2),c1,c2 = growx
if (b1==0 and b2==0):
x_up = [0,
L_EC-self.L_box_end + self.w_box/2*np.tan(angle_arc),
L_EC-self.L_box_end + self.w_box_end/2*np.tan(angle_arc),
L_EC + self.w_box_end/2*np.tan(angle_arc),
L_EC + (self.w_box_end/2+self.w_DT)*np.tan(angle_arc),
L_EC + (self.w_box_end/2+self.w_DT)*np.tan(angle_arc) - self.L_box_end - self.w_DT,
L_EC + (self.w_box_end/2+self.w_DT)*np.tan(angle_arc) - self.L_box_end - self.w_DT - (self.w_box_end-self.w_box)/2*np.tan(angle_arc),
0]
y_up = [-self.w_DT/2,
-self.w_DT/2,
-self.w_DT/2 + (self.w_box_end-self.w_box)/2,
-self.w_DT/2 + (self.w_box_end-self.w_box)/2,
-self.w_DT/2 + (self.w_box_end-self.w_box)/2+self.w_DT,
-self.w_DT/2 + (self.w_box_end-self.w_box)/2+self.w_DT,
self.w_DT/2,
self.w_DT/2,
]
_my_polygon(layer_wg=layers,vtx=np.c_[x_up,y_up]).put(self.L_in,self.w_box/2+self.w_DT/2,0)
x_down = [0,
L_EC-self.L_box_end - self.w_box/2*np.tan(angle_arc),
L_EC-self.L_box_end - self.w_box_end/2*np.tan(angle_arc),
L_EC - self.w_box_end/2*np.tan(angle_arc),
L_EC - (self.w_box_end/2+self.w_DT)*np.tan(angle_arc),
L_EC - (self.w_box_end/2+self.w_DT)*np.tan(angle_arc) - self.L_box_end - self.w_DT,
L_EC - (self.w_box_end/2+self.w_DT)*np.tan(angle_arc) - self.L_box_end - self.w_DT + (self.w_box_end-self.w_box)/2*np.tan(angle_arc),
0]
y_down = [self.w_DT/2,
self.w_DT/2,
self.w_DT/2 - (self.w_box_end-self.w_box)/2,
self.w_DT/2 - (self.w_box_end-self.w_box)/2,
self.w_DT/2 - (self.w_box_end-self.w_box)/2-self.w_DT,
self.w_DT/2 - (self.w_box_end-self.w_box)/2-self.w_DT,
-self.w_DT/2,
-self.w_DT/2,
]
_my_polygon(layer_wg=layers,vtx=np.c_[x_down,y_down]).put(self.L_in,-self.w_box/2-self.w_DT/2,0)
else:
dx = (self.w_box_end/2 + self.w_DT+b1)*np.tan(angle_arc)
dy = self.w_DT+self.w_box_end/2+b1
if (self.angle_tile !=0 ):
x_up = [-b1,
L_EC - 2*dx-(dy*dy/dx),
L_EC - 2*dx,
L_EC - dx,
L_EC + dx,
-b1]
y_up = [-dy,
-dy,
-2*dy,
-dy,
dy,
dy,
]
else:
x_up = [-b1,
L_EC - dx,
L_EC + dx,
-b1]
y_up = [-dy,
-dy,
dy,
dy,
]
_my_polygon(layer_wg=layers,vtx=np.c_[x_up,y_up]).put(self.L_in,0,0)
""" Corener patch """
nd.strt(xs=self.xs_Trench)
with nd.Cell(name=self.name,instantiate=self.instantiate) as C:
inst = EC_core.put('b0',0,0,180+self.angle_tile)
## revised in 2026.06.07 by Qin Yue
# legacy: inst.raise_pins(['a1','a1'])
inst.raise_pins(['opt_a1','opt_a1'])
nd.Pin(name="b0").put(0,0,0)
return C
+209 -8
View File
@@ -241,8 +241,12 @@ class Taper() :
linear_taper = strip.taper(
length=self.length,width1=self.width1,width2=self.width2,patch=True).put(0,0,0)
output_strt = strip.strt(length=0.5,width=self.width2).put()
nd.Pin(name="a1",width=self.width1).put(linear_taper.pin['a0'])
nd.Pin(name="b1",width=self.width2).put(output_strt.pin['b0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="a1",width=self.width1).put(linear_taper.pin['a0'])
nd.Pin(name="opt_a1",width=self.width1,type="optical:").put(linear_taper.pin['a0'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="b1",width=self.width2).put(output_strt.pin['b0'])
nd.Pin(name="opt_b1",width=self.width2,type="optical:").put(output_strt.pin['b0'])
else :
c2 = self.width1/2
c1 = (c2 - self.width2/2) / np.power(self.length, self.order)
@@ -273,8 +277,12 @@ class Taper() :
nd.strt(length=0.5, width=self.width2, xs='strip').put(self.length,0,0)
nd.Pin(name='a1',width=self.width1).put(0,0,180)
nd.Pin(name="b1",width=self.width2).put(self.length+0.5,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.width1).put(0,0,180)
nd.Pin(name='opt_a1',width=self.width1,type="optical:").put(0,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name="b1",width=self.width2).put(self.length+0.5,0,0)
nd.Pin(name="opt_b1",width=self.width2,type="optical:").put(self.length+0.5,0,0)
if self.show_pins :
nd.put_stub()
return ic
@@ -366,8 +374,12 @@ class Grating_2D_Hole() :
)
'''Generate the taper output.'''
taper = Taper(width1=self.w_gt, width2=self.w_wg, length=self.l_taper, type=self.type_taper)
taper_horizontal = taper.cell.put('a1', self.w_gt/2,0,0)
taper_vertical = taper.cell.put('a1',0,self.w_gt/2,90)
## revised in 2026.06.07 by Qin Yue
# legacy: taper_horizontal = taper.cell.put('a1', self.w_gt/2,0,0)
taper_horizontal = taper.cell.put('opt_a1', self.w_gt/2,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: taper_vertical = taper.cell.put('a1',0,self.w_gt/2,90)
taper_vertical = taper.cell.put('opt_a1',0,self.w_gt/2,90)
'''Generate the diffraction etched region.'''
theta_list = np.linspace(0, 2*np.pi, 32)
gt_ring_poly = [
@@ -383,8 +395,12 @@ class Grating_2D_Hole() :
polygon=polysi_ring_poly, vector=self.polysi_vector, layer=self.polysi_layer
).put(self.w_gt/2, self.w_gt/2)
'''Put the pin location'''
nd.Pin(name='g1').put(taper_horizontal.pin['b1'])
nd.Pin(name='g2').put(taper_vertical.pin['b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='g1').put(taper_horizontal.pin['b1'])
nd.Pin(name='g1').put(taper_horizontal.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='g2').put(taper_vertical.pin['b1'])
nd.Pin(name='g2').put(taper_vertical.pin['opt_b1'])
# nd.put_stub()
return ic
@@ -1257,6 +1273,191 @@ class GC_STD_1D:
nd.strt(xs=self.xs_wg,width=self.w_wg,length=dX_gc2gc).put(-dX_gc2gc/2,0,0)
return C
class GC_SiN_Si_Dual_Layer:
"""
GC SiN Si Dual Layer primitive component.
This component builds the GC SiN Si Dual Layer layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
w_teeth_SiN : list or float, optional
Width parameter in microns. Default is 0.5.
gap_teeth_SiN : list or float, optional
Spacing or gap parameter in microns. Default is 0.5.
w_teeth_Si : list or float, optional
Width parameter in microns. Default is 0.5.
gap_teeth_Si : list or float, optional
Spacing or gap parameter in microns. Default is 0.5.
ori_teeth_offset : float, optional
Value for the ori_teeth_offset parameter. Default is 5.0.
n_teeth_Si : float, optional
Value for the n_teeth_Si parameter. Default is 30.
n_teeth_SiN : float, optional
Value for the n_teeth_SiN parameter. Default is 30.
A_gc_taper : float, optional
Angle parameter in degrees. Default is 25.0.
R_teeth_ori_SiN : float, optional
Radius parameter in microns. Default is 40.0.
R_teeth_ori_Si : float, optional
Radius parameter in microns. Default is 40.0.
L_end_Si : float, optional
Length parameter in microns. Default is 0.2.
L_end_SiN : float, optional
Length parameter in microns. Default is 5.0.
w_port : float, optional
Width parameter in microns. Default is 0.9.
A_anti_rfl : float, optional
Angle parameter in degrees. Default is 4.0.
layer_SiN_slab : str, optional
Layer or cross-section name used by the device. Default is None.
layer_Si_slab : str, optional
Layer or cross-section name used by the device. Default is None.
layer_Si_teeth : str, optional
Layer or cross-section name used by the device. Default is None.
layer_SiN_teeth : str, optional
Layer or cross-section name used by the device. Default is None.
layer_SiN_etch : str, optional
Layer or cross-section name used by the device. Default is None.
layer_Si_etch : str, optional
Layer or cross-section name used by the device. Default is None.
layer_ox_open : str, optional
Layer or cross-section name used by the device. Default is None.
"""
def __init__(self,
name:str=None,
w_teeth_SiN:'list|float' = 0.5,
gap_teeth_SiN:'list|float' = 0.5,
w_teeth_Si:'list|float' = 0.5,
gap_teeth_Si:'list|float' = 0.5,
ori_teeth_offset:float = 5.0,
n_teeth_Si:float=30,
n_teeth_SiN:float=30,
A_gc_taper:float=25.0,
R_teeth_ori_SiN:float=40.0,
R_teeth_ori_Si:float=40.0,
L_end_Si:float=0.2,
L_end_SiN:float=5.0,
w_port : float = 0.9,
A_anti_rfl:float = 4.0,
layer_SiN_slab:str=None,
layer_Si_slab:str=None,
layer_Si_teeth:str=None,
layer_SiN_teeth:str=None,
layer_SiN_etch:str=None,
layer_Si_etch:str=None,
layer_ox_open:str=None,
):
self.name = name
self.w_teeth_SiN = w_teeth_SiN
self.gap_teeth_SiN = gap_teeth_SiN
self.w_teeth_Si = w_teeth_Si
self.gap_teeth_Si = gap_teeth_Si
self.ori_teeth_offset = ori_teeth_offset
self.n_teeth_SiN = n_teeth_SiN
self.n_teeth_Si = n_teeth_Si
self.A_gc_taper = A_gc_taper
self.w_port = w_port
self.L_end_Si = L_end_Si
self.L_end_SiN = L_end_SiN
self.A_anti_rfl = A_anti_rfl
self.R_teeth_ori_SiN = R_teeth_ori_SiN
self.R_teeth_ori_Si = R_teeth_ori_Si
self.layer_SiN_slab = layer_SiN_slab
self.layer_Si_slab = layer_Si_slab
self.layer_Si_teeth = layer_Si_teeth
self.layer_SiN_teeth = layer_SiN_teeth
self.layer_SiN_etch = layer_SiN_etch
self.layer_Si_etch = layer_Si_etch
self.layer_ox_open = layer_ox_open
self.cell = self.generate_gds()
def generate_gds(self):
""" creating instance cell or not """
if (self.name is None) : self.instantiate = False
else : self.instantiate = True
""" """
if (isinstance(self.w_teeth_SiN,list) or isinstance(self.w_teeth_SiN,np.ndarray)):
n_teeth_SiN = len(self.w_teeth_SiN)
elif (isinstance(self.w_teeth_SiN,float)):
n_teeth_SiN = self.n_teeth_SiN
w_teeth_SiN = [w_teeth_SiN]*n_teeth_SiN
""" """
if (isinstance(self.w_teeth_Si,list) or isinstance(self.w_teeth_Si,np.ndarray)):
n_teeth_Si = len(self.w_teeth_Si)
elif (isinstance(self.w_teeth_Si,float)):
n_teeth_Si = self.n_teeth_Si
w_teeth_Si = [w_teeth_Si]*n_teeth_Si
with nd.Cell(instantiate=self.instantiate, name=self.name) as C:
""" Creating SiN layer grating """
## whole area where the grating area covered
L_gc = self.R_teeth_ori_SiN + self.L_end_SiN + sum(self.w_teeth_SiN) + sum(self.gap_teeth_SiN)
w_box_gc = L_gc*np.sin(self.A_gc_taper/2*np.pi/180)*2
L_box_gc = L_gc*np.cos(self.A_gc_taper/2*np.pi/180)
x_slab = [0,L_box_gc,L_gc+w_box_gc*np.sin(self.A_anti_rfl*np.pi/180),L_gc,L_box_gc,0]
y_slab = [self.w_port/2,w_box_gc/2,w_box_gc/2,-w_box_gc/2,-w_box_gc/2,-self.w_port/2]
_my_polygon(layer_wg=self.layer_SiN_slab,vtx=np.c_[x_slab,y_slab]).put(0,0,0)
# circle(radius=self.R_teeth_ori_SiN/2,angle=self.A_gc_taper,layer=self.layer_SiN_slab,
# width=self.R_teeth_ori_SiN).cell.put(0,0,-self.A_gc_taper/2)
A_etch_ext = 4
## Placing teeth
r_in = self.R_teeth_ori_SiN
for idxT in range(0,n_teeth_SiN):
r_out = r_in + self.gap_teeth_SiN[idxT]
circle(radius=(r_out+r_in)/2,angle=self.A_gc_taper+A_etch_ext,layer=self.layer_SiN_etch,
width=self.gap_teeth_Si[idxT]).cell.put(0,0,-self.A_gc_taper/2-A_etch_ext/2)
r_in = r_out + self.w_teeth_SiN[idxT]
""" Creating Si layer grating """
w_Si_slab = sum(self.w_teeth_Si)+sum(self.gap_teeth_Si)
R_Si_slab = self.R_teeth_ori_Si+w_Si_slab/2
circle(radius=R_Si_slab,angle=self.A_gc_taper,layer=self.layer_Si_slab,
width=w_Si_slab).cell.put(0,0,-self.A_gc_taper/2)
## Placing teeth
r_in = self.R_teeth_ori_Si
for idxT in range(0,n_teeth_Si):
r_out = r_in + self.gap_teeth_Si[idxT]
if (self.layer_Si_etch is not None):
circle(radius=(r_out+r_in)/2,angle=self.A_gc_taper+A_etch_ext,layer=self.layer_Si_etch,
width=self.gap_teeth_Si[idxT]).cell.put(0,0,-self.A_gc_taper/2-A_etch_ext/2)
elif (self.layer_Si_teeth is not None):
circle(radius=r_out+(self.w_teeth_Si[idxT])/2,angle=self.A_gc_taper,layer=self.layer_Si_teeth,
width=self.w_teeth_Si[idxT]).cell.put(0,0,-self.A_gc_taper/2)
r_in = r_out + self.w_teeth_Si[idxT]
return C
class FA:
"""
FA primitive component.
+33 -11
View File
@@ -125,8 +125,12 @@ class MMI_ML:
_my_polygon(layer_wg=layers,vtx=vtx).put(0,0,0)
nd.Pin(name='a1',width=Wsg[0]).put(0,0,180)
nd.Pin(name='b1',width=Wsg[-1]).put(L,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=Wsg[0]).put(0,0,180)
nd.Pin(name='opt_a1',width=Wsg[0],type="optical:").put(0,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=Wsg[-1]).put(L,0,0)
nd.Pin(name='opt_b1',width=Wsg[-1],type="optical:").put(L,0,0)
""" For central MMI """
L_mmi = 0
@@ -159,17 +163,31 @@ class MMI_ML:
L = max(Lsg_mmi)+b1*2
nd.strt(length=L,layer=layers,width=w).put(-b1,0,0)
nd.Pin(name='a1',width=Wsg_mmi[0]).put(0,0,180)
nd.Pin(name='b1',width=Wsg_mmi[-1]).put(L_mmi,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=Wsg_mmi[0]).put(0,0,180)
nd.Pin(name='opt_a1',width=Wsg_mmi[0],type="optical:").put(0,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=Wsg_mmi[-1]).put(L_mmi,0,0)
nd.Pin(name='opt_b1',width=Wsg_mmi[-1],type="optical:").put(L_mmi,0,0)
for idx_in in range(0,self.N_in):
Arm_inst = Arm.put('b1',0,self.Dp_in*(-idx_in+(self.N_in-1)/2),180)
nd.Pin(name='a'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: Arm_inst = Arm.put('b1',0,self.Dp_in*(-idx_in+(self.N_in-1)/2),180)
Arm_inst = Arm.put('opt_b1',0,self.Dp_in*(-idx_in+(self.N_in-1)/2),180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put()
nd.Pin(name='opt_a'+str(round(idx_in+1)),pin=Arm_inst.pin['opt_a1'],type="optical:").put()
for idx_in in range(0,self.N_out):
Arm_inst = Arm.put('b1',L_mmi,self.Dp_out*(-idx_in+(self.N_out-1)/2),0)
nd.Pin(name='b'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put()
MMI.put('a1',0,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: Arm_inst = Arm.put('b1',L_mmi,self.Dp_out*(-idx_in+(self.N_out-1)/2),0)
Arm_inst = Arm.put('opt_b1',L_mmi,self.Dp_out*(-idx_in+(self.N_out-1)/2),0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put()
nd.Pin(name='opt_b'+str(round(idx_in+1)),pin=Arm_inst.pin['opt_a1'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: MMI.put('a1',0,0,0)
MMI.put('opt_a1',0,0,0)
if (show_pins):
nd.put_stub()
@@ -190,12 +208,16 @@ class MMI_ML:
pic_strip = Route(width=self.w_arm[0],radius=R_bend,xs=self.xs)
for idx_in in range(0,self.N_in):
GC = gc_cell.put('g1',-dX_gc2gc/2,dY_gc2gc*(-idx_in + (self.N_in-1)/2),180)
pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['a'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['a'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['opt_a'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
for idx_in in range(0,self.N_out):
toggle = np.mod(idx_in,2)-0.5
GC = gc_cell.put('g1', dX_gc2gc/2+Xout_offset*toggle,dY_gc2gc*(-idx_in + (self.N_out-1)/2),0)
pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['b'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['b'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['opt_b'+str(idx_in+1)],Lstart=dX_gc2gc/10).put()
return C
+6 -2
View File
@@ -206,11 +206,15 @@ class RacetrackResonator:
self.cell_bus = bus.cell
bus_instr = bus.cell.put(0,-self.dLy/2-bend_cell.sz[1]-self.w0/2-self.w1_bus/2-self.gap1,0)
bus_instr.raise_pins(['a1','b1'],['a1','b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: bus_instr.raise_pins(['a1','b1'],['a1','b1'])
bus_instr.raise_pins(['opt_a1','opt_b1'],['opt_a1','opt_b1'])
if (self.w2_bus > 0):
bus_instr = bus.cell.put(0, self.dLy/2+bend_cell.sz[1]+self.w0/2+self.w2_bus/2+self.gap2,0,flip=1)
bus_instr.raise_pins(['a1','b1'],['a2','b2'])
## revised in 2026.06.07 by Qin Yue
# legacy: bus_instr.raise_pins(['a1','b1'],['a2','b2'])
bus_instr.raise_pins(['opt_a1','opt_b1'],['opt_a2','opt_b2'])
return C
+69 -23
View File
@@ -222,13 +222,25 @@ class AED_ring :
elif(hasattr(self.cell_xs_transition,'cell')):
cell_trans = self.cell_xs_transition.cell
temp = cell_trans.put(bus.pin['a1'])
nd.Pin(name='a1',pin=temp.pin['b0']).put()
temp = cell_trans.put(bus.pin['b1'])
nd.Pin(name='b1',pin=temp.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = cell_trans.put(bus.pin['a1'])
temp = cell_trans.put(bus.pin['opt_a1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=temp.pin['b0']).put()
nd.Pin(name='opt_a1',pin=temp.pin['b0'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = cell_trans.put(bus.pin['b1'])
temp = cell_trans.put(bus.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=temp.pin['b0']).put()
nd.Pin(name='opt_b1',pin=temp.pin['b0'],type="optical:").put()
else:
nd.Pin(name='a1',pin=bus.pin['a1']).put()
nd.Pin(name='b1',pin=bus.pin['b1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',pin=bus.pin['a1']).put()
nd.Pin(name='opt_a1',pin=bus.pin['opt_a1'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',pin=bus.pin['b1']).put()
nd.Pin(name='opt_b1',pin=bus.pin['opt_b1'],type="optical:").put()
if show_pins:
nd.put_stub()
@@ -259,13 +271,25 @@ class AED_ring :
elif(hasattr(self.cell_xs_transition,'cell')):
cell_trans = self.cell_xs_transition.cell
temp = cell_trans.put(bus.pin['a1'])
nd.Pin(name='a2',pin=temp.pin['b0']).put()
temp = cell_trans.put(bus.pin['b1'])
nd.Pin(name='b2',pin=temp.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = cell_trans.put(bus.pin['a1'])
temp = cell_trans.put(bus.pin['opt_a1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',pin=temp.pin['b0']).put()
nd.Pin(name='opt_a2',pin=temp.pin['b0'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = cell_trans.put(bus.pin['b1'])
temp = cell_trans.put(bus.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',pin=temp.pin['b0']).put()
nd.Pin(name='opt_b2',pin=temp.pin['b0'],type="optical:").put()
else:
nd.Pin(name='a2',pin=bus.pin['a1']).put()
nd.Pin(name='b2',pin=bus.pin['b1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a2',pin=bus.pin['a1']).put()
nd.Pin(name='opt_a2',pin=bus.pin['opt_a1'],type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b2',pin=bus.pin['b1']).put()
nd.Pin(name='opt_b2',pin=bus.pin['opt_b1'],type="optical:").put()
if show_pins:
nd.put_stub()
@@ -293,23 +317,45 @@ class AED_ring :
pic_strip = Route(width=w_wg,radius=R_bend,xs=xs,MM_route=False)
if (self.w2_bus>0):
dX_c = abs(test_cell.pin['a1'].y - test_cell.pin['a2'].y)
dY_c = abs(test_cell.pin['a1'].x - test_cell.pin['a2'].x)
INSTR = test_cell.put('a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y-R_bend-1,-90,flip=0)
pic_strip.bend_p2p(pin1=INSTR.pin['a1'],pin2=GC1.pin['g1']).put()
pic_strip.bend_p2p(pin1=INSTR.pin['a2'],pin2=GC2.pin['g1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: dX_c = abs(test_cell.pin['a1'].y - test_cell.pin['a2'].y)
dX_c = abs(test_cell.pin['opt_a1'].y - test_cell.pin['opt_a2'].y)
## revised in 2026.06.07 by Qin Yue
# legacy: dY_c = abs(test_cell.pin['a1'].x - test_cell.pin['a2'].x)
dY_c = abs(test_cell.pin['opt_a1'].x - test_cell.pin['opt_a2'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: INSTR = test_cell.put('a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y-R_bend-1,-90,flip=0)
INSTR = test_cell.put('opt_a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y-R_bend-1,-90,flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.bend_p2p(pin1=INSTR.pin['a1'],pin2=GC1.pin['g1']).put()
pic_strip.bend_p2p(pin1=INSTR.pin['opt_a1'],pin2=GC1.pin['g1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.bend_p2p(pin1=INSTR.pin['a2'],pin2=GC2.pin['g1']).put()
pic_strip.bend_p2p(pin1=INSTR.pin['opt_a2'],pin2=GC2.pin['g1']).put()
GC3 = GC.put('g1',GC2.pin['g1'].x,GC2.pin['g1'].y-dY_gc2gc,0)
pic_strip.bend_p2p(pin1=INSTR.pin['b1'],pin2=GC3.pin['g1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.bend_p2p(pin1=INSTR.pin['b1'],pin2=GC3.pin['g1']).put()
pic_strip.bend_p2p(pin1=INSTR.pin['opt_b1'],pin2=GC3.pin['g1']).put()
pic_strip.bend_route(pin=INSTR.pin['b2'],length1=0.5,length2=0.5).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.bend_route(pin=INSTR.pin['b2'],length1=0.5,length2=0.5).put()
pic_strip.bend_route(pin=INSTR.pin['opt_b2'],length1=0.5,length2=0.5).put()
pic_strip.taper(width2=w_term,length=15).put()
else:
dX_c = abs(test_cell.pin['a1'].x - test_cell.pin['b1'].x)
INSTR = test_cell.put('a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y,0,flip=0)
pic_strip.strt_p2p(pin1=INSTR.pin['a1'],pin2=GC1.pin['g1']).put()
pic_strip.strt_p2p(pin1=INSTR.pin['b1'],pin2=GC2.pin['g1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: dX_c = abs(test_cell.pin['a1'].x - test_cell.pin['b1'].x)
dX_c = abs(test_cell.pin['opt_a1'].x - test_cell.pin['opt_b1'].x)
## revised in 2026.06.07 by Qin Yue
# legacy: INSTR = test_cell.put('a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y,0,flip=0)
INSTR = test_cell.put('opt_a1',GC1.pin['g1'].x + dX_gc2gc/2-dX_c/2-R_bend-offset,GC1.pin['g1'].y,0,flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.strt_p2p(pin1=INSTR.pin['a1'],pin2=GC1.pin['g1']).put()
pic_strip.strt_p2p(pin1=INSTR.pin['opt_a1'],pin2=GC1.pin['g1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: pic_strip.strt_p2p(pin1=INSTR.pin['b1'],pin2=GC2.pin['g1']).put()
pic_strip.strt_p2p(pin1=INSTR.pin['opt_b1'],pin2=GC2.pin['g1']).put()
INSTR.raise_pins()
nd.Pin(name='a0').put(0,0,180)
+75 -25
View File
@@ -234,14 +234,18 @@ class spiral:
SPR_U = Conchoid(R0=R_act,kR=kR,T=self.cycles*pi,w=self.width*(a1-a2)+(b1-b2),
layer=layers,final_flat=None,begin_flat=None,res=self.res)
# layer=layers,final_flat=0,begin_flat=spr_bend.vtx_center[-1,0]/spr_bend.vtx_center[-1,1],res=self.res)
SPR_U_INST = SPR_U.cell.put('a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: SPR_U_INST = SPR_U.cell.put('a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90,flip=1)
SPR_U_INST = SPR_U.cell.put('opt_a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90,flip=1)
""" relative part """
SPR_D = Conchoid(R0=R_act,kR=kR,T=self.cycles*pi+pi-self.port_angle/180*np.pi,w=self.width*(a1-a2)+(b1-b2),layer=layers,
final_flat=None,
begin_flat=None,res=self.res)
# begin_flat=spr_bend.vtx_center[-1,0]/spr_bend.vtx_center[-1,1],res=self.res)
SPR_D_INST = SPR_D.cell.put('a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: SPR_D_INST = SPR_D.cell.put('a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90,flip=1)
SPR_D_INST = SPR_D.cell.put('opt_a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90,flip=1)
if (self.sharp_patch==True and b1!=0 and b2!=0):
sz = (R_act+pitch*self.cycles+self.port_angle/180*np.pi*kR + self.width*a1+b1)*2
@@ -251,14 +255,26 @@ class spiral:
self.Ru = SPR_U.R_end
self.Rd = SPR_D.R_end
if (self.width!=self.w_port):
nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_U_INST.pin['b1'])
nd.Pin(name='a1',width=self.w_port).put()
nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_D_INST.pin['b1'])
nd.Pin(name='b1',width=self.w_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_U_INST.pin['b1'])
nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_U_INST.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_port).put()
nd.Pin(name='opt_a1',width=self.w_port,type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_D_INST.pin['b1'])
nd.taper(xs=self.xs,width1=self.width,width2=self.w_port,length=self.Ltp_port).put(SPR_D_INST.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_port).put()
nd.Pin(name='opt_b1',width=self.w_port,type="optical:").put()
else :
nd.Pin(name='a1',width=self.w_port).put(SPR_U_INST.pin['b1'])
nd.Pin(name='b1',width=self.width).put(SPR_D_INST.pin['b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_port).put(SPR_U_INST.pin['b1'])
nd.Pin(name='opt_a1',width=self.w_port,type="optical:").put(SPR_U_INST.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.width).put(SPR_D_INST.pin['b1'])
nd.Pin(name='opt_b1',width=self.width,type="optical:").put(SPR_D_INST.pin['opt_b1'])
if show_pins:
nd.put_stub()
@@ -281,8 +297,12 @@ class spiral:
else:
with nd.Cell(instantiate=False) as bend_cell:
inst = circle(radius=self.R_bend,width=self.width,theta_start=0,theta_stop=90,xs=self.xs,res=self.res,sharp_patch=self.sharp_patch).cell.put(0,0,0)
nd.Pin(name='a0',pin=inst.pin['a1']).put()
nd.Pin(name='b0',pin=inst.pin['b1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a0',pin=inst.pin['a1']).put()
nd.Pin(name='a0',pin=inst.pin['opt_a1']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b0',pin=inst.pin['b1']).put()
nd.Pin(name='b0',pin=inst.pin['opt_b1']).put()
bend_sz = [self.R_bend,self.R_bend]
L_bend = np.pi/2*self.R_bend
@@ -379,19 +399,31 @@ class spiral:
if (self.w_port !=self.width) :
if (self.rib2strip):
nd.taper(length=self.Ltp_port,width1=self.width,width2=self.w_port,xs='strip').put(pin_D_pre)
nd.Pin(name='b1',width=self.w_bend_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_bend_port).put()
nd.Pin(name='opt_b1',width=self.w_bend_port,type="optical:").put()
nd.taper(length=self.Ltp_port,width1=self.width,width2=self.w_port,xs='strip').put(pin_U_pre)
nd.Pin(name='a1',width=self.w_bend_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_bend_port).put()
nd.Pin(name='opt_a1',width=self.w_bend_port,type="optical:").put()
else :
nd.taper(length=self.Ltp_port,width1=self.width,width2=self.w_port,xs=self.xs).put(pin_D_pre)
nd.Pin(name='b1',width=self.w_bend_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_bend_port).put()
nd.Pin(name='opt_b1',width=self.w_bend_port,type="optical:").put()
nd.taper(length=self.Ltp_port,width1=self.width,width2=self.w_port,xs=self.xs).put(pin_U_pre)
nd.Pin(name='a1',width=self.w_bend_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_bend_port).put()
nd.Pin(name='opt_a1',width=self.w_bend_port,type="optical:").put()
else:
nd.Pin(name='b1',width=self.w_bend_port).put(pin_D_pre)
nd.Pin(name='a1',width=self.w_bend_port).put(pin_U_pre)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_bend_port).put(pin_D_pre)
nd.Pin(name='opt_b1',width=self.w_bend_port,type="optical:").put(pin_D_pre)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_bend_port).put(pin_U_pre)
nd.Pin(name='opt_a1',width=self.w_bend_port,type="optical:").put(pin_U_pre)
self.L = L
@@ -745,8 +777,12 @@ class spiral_rectangle:
taper = self.cell_xs_transition.put(pin_U_pre)
pin_U_pre = taper.pin['b0']
nd.Pin(name='b1',width=self.w_port).put(pin_D_pre)
nd.Pin(name='a1',width=self.w_port).put(pin_U_pre)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_port).put(pin_D_pre)
nd.Pin(name='opt_b1',width=self.w_port,type="optical:").put(pin_D_pre)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_port).put(pin_U_pre)
nd.Pin(name='opt_a1',width=self.w_port,type="optical:").put(pin_U_pre)
self.L = L
@@ -1088,7 +1124,9 @@ class spiral_circle:
# print("")
SPR_U_INST = SPR_U.cell.put('a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90 + Arot,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: SPR_U_INST = SPR_U.cell.put('a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90 + Arot,flip=1)
SPR_U_INST = SPR_U.cell.put('opt_a1',IN_L.pin['b0'].x,IN_L.pin['b0'].y,90 + Arot,flip=1)
w_cur = self.width*(a1-a2)+(b1-b2)
## adding connection patch
@@ -1102,11 +1140,15 @@ class spiral_circle:
res=self.res)
SPR_D_INST = SPR_D.cell.put('a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90 + Arot,flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: SPR_D_INST = SPR_D.cell.put('a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90 + Arot,flip=1)
SPR_D_INST = SPR_D.cell.put('opt_a1',IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90 + Arot,flip=1)
nd.taper(layer=layers,width1=w_cur,width2=w_cur-0.01,length=0.01).put(IN_R.pin['b0'].x,IN_R.pin['b0'].y,-90-self.Atilt+Arot)
nd.taper(layer=layers,width1=w_cur,width2=w_cur-0.01,length=0.01).put(IN_R.pin['b0'].x,IN_R.pin['b0'].y, 90-self.Atilt+Arot)
self.Rmax = np.sqrt(SPR_D_INST.pin['b1'].x**2 + SPR_D_INST.pin['b1'].y**2)
## revised in 2026.06.07 by Qin Yue
# legacy: self.Rmax = np.sqrt(SPR_D_INST.pin['b1'].x**2 + SPR_D_INST.pin['b1'].y**2)
self.Rmax = np.sqrt(SPR_D_INST.pin['opt_b1'].x**2 + SPR_D_INST.pin['opt_b1'].y**2)
if (self.sharp_patch==True and b1!=0 and b2!=0):
sz = (R_act+pitch*self.cycles+self.port_angle/180*np.pi*kR + self.width*a1+b1)*2
@@ -1116,10 +1158,18 @@ class spiral_circle:
self.Ru = SPR_U.R_end
self.Rd = SPR_D.R_end
nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_U_INST.pin['b1'])
nd.Pin(name='a1',width=self.w_port).put()
nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_D_INST.pin['b1'])
nd.Pin(name='b1',width=self.w_port).put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_U_INST.pin['b1'])
nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_U_INST.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=self.w_port).put()
nd.Pin(name='opt_a1',width=self.w_port,type="optical:").put()
## revised in 2026.06.07 by Qin Yue
# legacy: nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_D_INST.pin['b1'])
nd.taper(xs=self.xs,width1=self.w_port,width2=self.w_port,length=self.Lport).put(SPR_D_INST.pin['opt_b1'])
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=self.w_port).put()
nd.Pin(name='opt_b1',width=self.w_port,type="optical:").put()
if show_pins:
nd.put_stub()
+12 -4
View File
@@ -199,9 +199,13 @@ class taper_xs2xs:
nd.strt(length=L_port,xs=xs_2,width=w_2).put(L_taper,0,0)
nd.Pin(name='a0',width=w_1).put(-L_port,0,180)
nd.Pin(name='a1',width=w_1).put(-L_port,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=w_1).put(-L_port,0,180)
nd.Pin(name='opt_a1',width=w_1,type="optical:").put(-L_port,0,180)
nd.Pin(name='b0',width=w_2).put(L_taper+L_port,0,0)
nd.Pin(name='b1',width=w_2).put(L_taper+L_port,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=w_2).put(L_taper+L_port,0,0)
nd.Pin(name='opt_b1',width=w_2,type="optical:").put(L_taper+L_port,0,0)
self.cell = C
@@ -363,8 +367,12 @@ class PSR:
nd.strt(width=w0,length=L_port,layer=layers).put(0,0,180)
nd.strt(width=w1,length=L_port,layer=layers).put(sum(Lt_rib),0,0)
nd.Pin(name='a1',width=w[0]).put(-L_port,0,180)
nd.Pin(name='b1',width=w[-1]).put(sum(Lt_rib)+L_port,0,0)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='a1',width=w[0]).put(-L_port,0,180)
nd.Pin(name='opt_a1',width=w[0],type="optical:").put(-L_port,0,180)
## revised in 2026.06.07 by Qin Yue
# legacy: nd.Pin(name='b1',width=w[-1]).put(sum(Lt_rib)+L_port,0,0)
nd.Pin(name='opt_b1',width=w[-1],type="optical:").put(sum(Lt_rib)+L_port,0,0)
self.cell = C