429 lines
17 KiB
Python
429 lines
17 KiB
Python
from typing import Any, Optional
|
|
import nazca as nd
|
|
import numpy as np
|
|
from .couplers import ring_bus_wg
|
|
|
|
from .taper import taper_xs2xs
|
|
|
|
from ...geometry import *
|
|
# import nazca.interconnects as IC
|
|
from ...routing import Route
|
|
|
|
from ...basic import __cell_arg__
|
|
|
|
# class Route(IC.Interconnect):
|
|
# pass
|
|
# from ...routing import *
|
|
|
|
|
|
""" 2023.03.19 REVISED """
|
|
""" NOTE: n_points will not be used in any future class, res will be the accurancy parameter """
|
|
|
|
class AED_ring :
|
|
"""
|
|
AED ring primitive component.
|
|
|
|
This component builds the AED ring layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
ORx : float, optional
|
|
Value for the ORx parameter. Default is 10.
|
|
ORy : float, optional
|
|
Value for the ORy parameter. Default is 10.
|
|
IRx : float, optional
|
|
Value for the IRx parameter. Default is 10 - 0.45.
|
|
IRy : float, optional
|
|
Value for the IRy parameter. Default is 10 - 0.65.
|
|
gap1 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
gap2 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w1_bus : float, optional
|
|
Value for the w1_bus parameter. Default is 0.45.
|
|
w2_bus : float, optional
|
|
Value for the w2_bus parameter. Default is 0.45.
|
|
R1_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
R2_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
A1_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
A2_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
offset_X : float, optional
|
|
Value for the offset_X parameter. Default is 0.
|
|
offset_Y : float, optional
|
|
Value for the offset_Y parameter. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R1_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
R1_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A1_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
A2_att : float, optional
|
|
Angle parameter in degrees. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
Euler_trasition : bool, optional
|
|
Value for the Euler_trasition parameter. Default is False.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.01.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
"""
|
|
def __init__(self,
|
|
name: Optional[str]=None,
|
|
ORx: float = 10,
|
|
ORy: float = 10,
|
|
IRx: float = 10-0.45,
|
|
IRy: float = 10-0.65,
|
|
gap1: float = 0.2,
|
|
gap2: float = 0.2,
|
|
w1_bus: float = 0.45,
|
|
w2_bus: float = 0.45,
|
|
R1_cp: Any = None,
|
|
R2_cp: Any = None,
|
|
A1_cp: int = 0,
|
|
A2_cp: int = 0,
|
|
offset_X: float=0,
|
|
offset_Y: float=0,
|
|
|
|
w_wg: float = 0.45,
|
|
R1_att: float = 20,
|
|
R2_att: float = 20,
|
|
R2_att_min: float= 10,
|
|
R1_att_min: float = 10,
|
|
A1_att: float = 30,
|
|
A2_att: float = 20,
|
|
|
|
Ltp_bus: int = 10,
|
|
dL_p2p: Optional[float] = None,
|
|
L_tilt: int = 10,
|
|
xs: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
Euler_trasition: bool = False,
|
|
res: float = 0.01, ## default to 1nm accurancy
|
|
show_pins: bool=False) -> None:
|
|
|
|
|
|
self.name = name
|
|
if (self.name==None):
|
|
self.instantiate = False
|
|
else :
|
|
self.instantiate = True
|
|
|
|
self.ORx = ORx
|
|
self.ORy = ORy
|
|
self.IRx = IRx
|
|
self.IRy = IRy
|
|
self.gap1 = gap1
|
|
self.gap2 = gap2
|
|
self.w1_bus = w1_bus
|
|
self.w2_bus = w2_bus
|
|
self.R1_cp = R1_cp
|
|
self.R2_cp = R2_cp
|
|
self.A1_cp = A1_cp
|
|
self.A2_cp = A2_cp
|
|
|
|
self.offset_X = offset_X
|
|
self.offset_Y = offset_Y
|
|
|
|
self.L_tilt = L_tilt
|
|
|
|
self.w_wg = w_wg
|
|
self.R1_att = R1_att
|
|
self.R1_att_min = R1_att_min
|
|
self.A1_att = A1_att
|
|
self.R2_att = R2_att
|
|
self.R2_att_min = R2_att_min
|
|
self.A2_att = A2_att
|
|
|
|
self.Ltp_bus = Ltp_bus
|
|
self.dL_p2p = dL_p2p
|
|
|
|
self.xs = xs
|
|
self.sharp_patch = sharp_patch
|
|
self.show_pins = show_pins
|
|
self.cell_xs_transition = cell_xs_transition
|
|
self.Euler_trasition = Euler_trasition
|
|
# self.n_points = n_points
|
|
self.res = res
|
|
|
|
self.cell = self.generate_pic_gds(sharp_patch=sharp_patch,show_pins=show_pins)
|
|
self.pic_cell = self.cell
|
|
|
|
def generate_pic_gds(self,sharp_patch,show_pins):
|
|
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
|
|
|
|
Rb = min([self.ORx+self.IRx,self.ORy+self.IRy])/2
|
|
Ra = max([self.ORx+self.IRx,self.ORy+self.IRy])/2
|
|
_L_perimeter_ = 2*pi*Rb + 4*(Ra-Rb)
|
|
|
|
|
|
""" Placing the central ring """
|
|
Elipse_dual(xs=self.xs,ORy=self.ORy,ORx=self.ORx,IRx=self.IRx,IRy=self.IRy,
|
|
offset_X=self.offset_X,offset_Y=self.offset_Y,sharp_patch=sharp_patch,
|
|
# n_points=self.n_points,
|
|
res=self.res).cell.put(0,0,0)
|
|
|
|
""" FATAL ERROR: REVISED IN 2022.09.19 """
|
|
if (self.R1_cp == None):
|
|
# self.R1_cp = self.r_ring+self.gap1+self.w1_bus/1+self.w_ring/2
|
|
self.R1_cp = self.ORy+self.gap1+self.w1_bus/2
|
|
|
|
if (self.xs!='strip'):
|
|
end_patch = True
|
|
else :
|
|
end_patch = False
|
|
|
|
bus_class = ring_bus_wg(xs=self.xs, R_cp=self.R1_cp,
|
|
w_bus=self.w1_bus,bend_DC=True, w_wg=self.w_wg, dAc=self.A1_cp,
|
|
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
|
|
|
|
R_max_trans=self.R1_att,dA_trans=self.A1_att,dL_trans=self.L_tilt,
|
|
R_max_anti=self.R1_att,R_min_anti=self.R1_att_min,
|
|
|
|
sharp_patch=self.sharp_patch,show_pins=show_pins,
|
|
wg_Ltp=self.Ltp_bus,w_trans=self.w1_bus,
|
|
dL_p2p=self.dL_p2p,
|
|
res=self.res, ## Added in 2023.1.3, to simplfy the points in coupler
|
|
end_patch=end_patch
|
|
# ).cell.put(0,-(self.r_ring+self.gap1+self.w1_bus/1+self.w_ring/2))
|
|
)
|
|
bus = bus_class.cell
|
|
self.bus = bus_class
|
|
self.cell_bus = bus
|
|
bus = bus.put(0,-(self.ORy+self.gap1+self.w1_bus/2))
|
|
|
|
""" xs transition refreshed in 2023.05.16 """
|
|
if (self.cell_xs_transition!=None):
|
|
if (isinstance(self.cell_xs_transition,nd.Cell)):
|
|
cell_trans = self.cell_xs_transition
|
|
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()
|
|
else:
|
|
nd.Pin(name='a1',pin=bus.pin['a1']).put()
|
|
nd.Pin(name='b1',pin=bus.pin['b1']).put()
|
|
|
|
if show_pins:
|
|
nd.put_stub()
|
|
|
|
## The upper coupling bus ##
|
|
if self.w2_bus >0:
|
|
if (self.R2_cp == None):
|
|
self.R2_cp = self.ORy+self.gap2+self.w2_bus/2
|
|
|
|
bus = ring_bus_wg(xs=self.xs, R_cp=self.R2_cp,
|
|
w_bus=self.w2_bus,bend_DC=True, w_wg=self.w_wg, dAc=self.A2_cp,
|
|
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
|
|
|
|
R_max_trans=self.R2_att,dA_trans=self.A2_att,dL_trans=self.L_tilt,
|
|
R_max_anti=self.R2_att,R_min_anti=self.R2_att_min,
|
|
|
|
sharp_patch=self.sharp_patch,show_pins=show_pins,
|
|
wg_Ltp=self.Ltp_bus,w_trans=self.w2_bus,
|
|
dL_p2p=self.dL_p2p,
|
|
res=self.res, ## Added in 2023.1.3, to simplfy the points in coupler
|
|
end_patch=end_patch
|
|
|
|
).cell.put(0,(self.ORy+self.gap2+self.w2_bus/2),flip=1)
|
|
|
|
if (self.cell_xs_transition!=None):
|
|
if (isinstance(self.cell_xs_transition,nd.Cell)):
|
|
cell_trans = self.cell_xs_transition
|
|
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()
|
|
else:
|
|
nd.Pin(name='a2',pin=bus.pin['a1']).put()
|
|
nd.Pin(name='b2',pin=bus.pin['b1']).put()
|
|
|
|
if show_pins:
|
|
nd.put_stub()
|
|
|
|
return C
|
|
|
|
def generate_test_gds(self,GC,dX_gc2gc,dY_gc2gc,offset=0,w_wg=0.45,w_term=0.18,R_bend=10,xs='strip',cell_attribute=None):
|
|
|
|
if (cell_attribute==None):
|
|
test_cell = self.cell
|
|
else :
|
|
test_cell = getattr(self,cell_attribute)
|
|
|
|
if (self.name!=None):
|
|
test_c_name = self.name + "_test"
|
|
else :
|
|
test_c_name = "AED_ring_test_NO"
|
|
|
|
with nd.Cell(name=test_c_name,instantiate=True) as C:
|
|
|
|
GC = __cell_arg__(arg=GC,arg_name="GC",func_name="AED_rings::generate_test_gds")
|
|
GC1 = GC.put('g1',0,0,180)
|
|
GC2 = GC.put('g1',dX_gc2gc,0,0)
|
|
|
|
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()
|
|
|
|
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()
|
|
|
|
pic_strip.bend_route(pin=INSTR.pin['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()
|
|
|
|
INSTR.raise_pins()
|
|
nd.Pin(name='a0').put(0,0,180)
|
|
nd.Pin(name='b0').put(0,0,0)
|
|
return C
|
|
|
|
class STD_PIC_Rings(AED_ring):
|
|
"""
|
|
STD PIC Rings primitive component.
|
|
|
|
This component builds the STD PIC Rings layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 10.
|
|
gap1 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
gap2 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w1_bus : float, optional
|
|
Value for the w1_bus parameter. Default is 0.45.
|
|
w2_bus : float, optional
|
|
Value for the w2_bus parameter. Default is 0.
|
|
R1_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
R2_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
A1_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
A2_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
offset_X : float, optional
|
|
Value for the offset_X parameter. Default is 0.
|
|
offset_Y : float, optional
|
|
Value for the offset_Y parameter. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R1_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
R1_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A1_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
A2_att : float, optional
|
|
Angle parameter in degrees. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
Euler_trasition : bool, optional
|
|
Value for the Euler_trasition parameter. Default is False.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.001.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
"""
|
|
def __init__(self,
|
|
name: Optional[str] = None,
|
|
r_ring: float=10,
|
|
w_ring: float=10,
|
|
|
|
gap1: float=0.2,
|
|
gap2: float=0.2,
|
|
w1_bus: float=0.45,
|
|
w2_bus: float=0,
|
|
R1_cp: Any=None,
|
|
R2_cp: Any=None,
|
|
A1_cp: int=0,
|
|
A2_cp: int=0,
|
|
offset_X: float=0,
|
|
offset_Y: float=0,
|
|
w_wg: float=0.45,
|
|
R1_att: float = 20,
|
|
R2_att: float = 20,
|
|
R2_att_min: float = 10,
|
|
R1_att_min: float = 10,
|
|
A1_att: float = 30,
|
|
A2_att: float = 20,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float]=None,
|
|
L_tilt: int=10,
|
|
xs: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
Euler_trasition: bool=False,
|
|
res: float = 0.001,
|
|
show_pins: bool=False) -> None:
|
|
|
|
ORx = r_ring+w_ring/2
|
|
ORy = r_ring+w_ring/2
|
|
IRx = r_ring-w_ring/2
|
|
IRy = r_ring-w_ring/2
|
|
|
|
|
|
super().__init__(name,
|
|
ORx,
|
|
ORy,
|
|
IRx, IRy, gap1, gap2, w1_bus, w2_bus, R1_cp, R2_cp, A1_cp, A2_cp, offset_X, offset_Y, w_wg,
|
|
R1_att, R2_att, R2_att_min, R1_att_min, A1_att, A2_att, Ltp_bus, dL_p2p, L_tilt, xs, sharp_patch, cell_xs_transition, Euler_trasition, res=res,
|
|
show_pins=show_pins) |