Files
mxpic_forge/mxpic/components/primitives/pic/spiral.py
T
2026-06-06 16:43:26 +08:00

1278 lines
58 KiB
Python

from typing import Any, Optional
from turtle import shape
import nazca as nd
import numpy as np
import math
from .taper import taper_xs2xs
from ...routing import Route
from ...geometry import *
from ....technologies import *
from ...geometry import _my_polygon,Conchoid,_my_poly_spiral
from scipy import optimize
class spiral:
"""
spiral primitive component.
This component builds the spiral layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
shape : str, optional
Value for the shape parameter. Default is 'circle'.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
R_bend : float, optional
Radius parameter in microns. Default is 10.
Rmin_euler : float, optional
Radius parameter in microns. Default is 10.
Lmin : float, optional
Length parameter in microns. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is 0.45.
w_bend_center : float, optional
Width parameter in microns. Default is 1.
Rmin_bend_center : float, optional
Radius parameter in microns. Default is 10.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
w_bend_port : Optional[float], optional
Width parameter in microns. Default is None.
Ltp_port : int, optional
Length parameter in microns. Default is 10.
res : float, optional
Value for the res parameter. Default is 0.5.
rib2strip : bool, optional
Value for the rib2strip parameter. Default is True.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
Euler_bend : bool, optional
Value for the Euler_bend parameter. Default is False.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
"""
def __init__(self,
name: str = None,
shape: str = 'circle',
Dmin: float = 50,
R_bend: float = 10,
Rmin_euler: float = 10,
Lmin: float = 50,
width: float = 2,
w_port: float = 0.45, ## not used at this moment
w_bend_center: float = 1,
Rmin_bend_center: float = 10,
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
w_bend_port: Optional[float]=None,
Ltp_port: int = 10,
# Tres: int = 256,## resolution for one cycle, these two parameters aborted in 2023.1.4
# Bres: int = 64, ## resolution for bends, these two parameters aborted in 2023.1.4
res : float = 0.5, ## added in 2023.1.4, the length resolution
rib2strip: bool=True,
port_angle: float = 180,
Euler_bend: bool = False,
show_pins: bool = False,
sharp_patch:bool = True
) -> None:
"""_summary_
Args:
name (str, optional): Name of the internal cell. Defaults to None.
shape (str, optional): circular or rectangular. Defaults to 'circle'.
Dmin (float, optional): Mimimum internal distance. Defaults to 50.
R_bend (float, optional): Radius of the bends. Defaults to 10.
Rmin_euler (float, optional): _description_. Defaults to 10.
Lmin (float, optional): Minimum length of the inner cycle. Defaults to 50.
width (float, optional): _description_. Defaults to 2.
w_port (float, optional): _description_. Defaults to 0.45.
w_bend_center (float, optional): _description_. Defaults to 1.
Rmin_bend_center (float, optional): _description_. Defaults to 10.
gap (float, optional): _description_. Defaults to 1.
cycles (float, optional): _description_. Defaults to 20.
xs (str, optional): _description_. Defaults to 'strip'.
layer (str, optional): _description_. Defaults to None.
Tres (int, optional): _description_. Defaults to 256.
port_angle (float, optional): _description_. Defaults to 90.
Euler_bend (bool, optional): _description_. Defaults to 'Euler'.
show_pins (bool, optional): _description_. Defaults to True.
sharp_patch (bool, optional): _description_. Defaults to True.
"""
self.Dmin = Dmin
self.Lmin = Lmin
self.R_bend = R_bend
self.shape = shape
self.cycles = cycles
self.width = width
self.w_port = w_port
self.gap = gap
self.xs = xs
self.layer = layer
self.name=name
if (self.name==None):
self.instantiate = False
else :
self.instantiate = True
self.port_angle=port_angle
self.w_bend_center= w_bend_center
self.Rmin_bend_center= Rmin_bend_center
self.Euler_bend= Euler_bend
self.Rmin_euler= Rmin_euler
self.sharp_patch= sharp_patch
self.w_bend_port = w_bend_port
self.Ltp_port = Ltp_port
self.rib2strip = rib2strip
self.res = res
self.cell = self.generate_gds(show_pins=show_pins)
def __strt_with_taper__(self,width1,width2,xs,length,Ltp=15,Lstart=2):
with nd.Cell(instantiate=False) as C:
L_mm = length-Ltp*2-Lstart*2
if (L_mm>0):
instr_a1 = nd.strt(length=Lstart,width=width1,xs=xs).put(0,0,0)
nd.taper(length=Ltp,width1=width1,width2=width2,xs=xs).put()
nd.strt(length=L_mm,width=width2,xs=xs).put()
nd.taper(length=Ltp,width1=width2,width2=width1,xs=xs).put()
instr_b1 = nd.strt(length=Lstart,width=width1,xs=xs).put()
else :
instr_a1 = nd.strt(length=length/2,width=width1,xs=xs).put(0,0,0)
instr_b1 = nd.strt(length=length/2,width=width1,xs=xs).put()
nd.Pin(name='a0',pin=instr_a1.pin['a0']).put()
nd.Pin(name='b0',pin=instr_b1.pin['b0']).put()
return C
def generate_gds(self,show_pins):
if (self.w_port==None):
self.w_port = self.width
if (self.w_bend_port==None):
self.w_bend_port = self.width
""" Circular Spiral """
if (self.shape=='circle'):
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
if (self.layer==None):
pitch = (self.width+self.gap)*2 ## a bi-twsited circle
Dmin = self.Dmin
R0 = Dmin/2
kR = pitch/(np.pi*2)
K_att = (np.power(R0,2)+2*np.power(kR,2))/np.power((np.power(R0,2)+np.power(kR,2)),1.5)
R_att = 1/K_att
for layers,growx,growy,acc in nd.layeriter(xs=self.xs):
(a1,b1), (a2,b2),c1,c2 = growx
""" Generating Central Euler bend """
if (self.Euler_bend == True):
""" Modified in 2023.07.31, Clothoid simplified into the simple attachment of Clothoid and Conchoid
No Angle compensation were build due to no significant improvement
"""
# spr_bend = Clothoid(xs=self.xs,R=[R_att/1.5,R_att/2.4,R_att],
spr_bend = Clothoid(xs=self.xs,R=[R_att,R_att/2.5001,R_att],
w=[self.w_bend_center,self.w_bend_port],A=[0,90,180],dL_wg=self.res,width_type='dual_sine')
else :
""" Genreating Circular bend for center """
spr_bend = Clothoid(xs=self.xs,R=[R0/2,R0/2,R0/2],
w=[self.w_bend_port,self.w_bend_port],A=[0,90,180],dL_wg=self.res,width_type='dual_sine')
w_cur = self.width*(a1-a2)+(b1-b2)
if (w_cur<pitch or self.sharp_patch==False):
Atilt = np.arctan(spr_bend.vtx_center[-1,0]/spr_bend.vtx_center[-1,1])*180/pi
Atilt = 0
self.Atilt = Atilt
print("Distance ",np.sqrt(abs(spr_bend.vtx_center[-1,0])**2 + abs(spr_bend.vtx_center[-1,1])**2))
IN_L = spr_bend.cell.put('a0',0,0,-90-Atilt,flip=1)
IN_R = spr_bend.cell.put('a0',0,0, 90-Atilt,flip=1)
R_act = spr_bend.sz[1]*np.cos(Atilt/180*np.pi)
R_act = spr_bend.sz[1]
R_act = np.abs(IN_L.pin['b0'].x)
""" Standard part """
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)
""" 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)
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
nd.strt(length=sz,width=sz,layer=layers).put(-sz/2,0,0)
self.L = SPR_U.L+SPR_D.L
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()
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'])
if show_pins:
nd.put_stub()
elif (self.shape=='rectangle'):
""" Rectangluar Spiral """
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
pitch = (self.width+self.gap)*2 ## a bi-twsited circle
if (self.Euler_bend == True):
bend_rt = Clothoid(xs=self.xs,R=[self.R_bend,self.Rmin_euler,self.R_bend],
w=[self.w_bend_port,self.w_bend_center,self.w_bend_port],A=[0,45,90],dL_wg=self.res,end_patch=False,sharp_patch=self.sharp_patch)
bend_cell = bend_rt.cell
bend_sz = bend_rt.sz
L_bend = bend_rt.L0
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()
bend_sz = [self.R_bend,self.R_bend]
L_bend = np.pi/2*self.R_bend
self.bend_cell = bend_cell
if (self.Dmin < bend_sz[1]*2):
self.Dmin = bend_sz[1]*2
print("WARNING: In <mxpic::passive::spiral>, Dmin too small")
D_port = self.Dmin - bend_sz[1]*2
with nd.Cell(instantiate=False) as wg_mid_cell:
wg = self.__strt_with_taper__(length=self.Lmin-bend_sz[0]*2,width2=self.width,width1=bend_cell.pin['a0'].width,xs=self.xs,Ltp=self.Ltp_port).put(-self.Lmin/2+bend_sz[0]*2,0,0)
bend_cell.put(wg.pin['a0'],flip=1)
self.__strt_with_taper__(length=D_port,width2=self.width,width1=bend_cell.pin['a0'].width,xs=self.xs,Ltp=self.Ltp_port).put()
bd = bend_cell.put(flip=0)
nd.Pin(name='a0',pin=bd.pin['b0']).put()
nd.Pin(name='b0',pin=wg.pin['b0']).put()
wg_mid = wg_mid_cell.put(-self.Lmin/2,self.Dmin/2,0)
pin_U_pre = wg_mid.pin['b0']
pin_D_pre = wg_mid.pin['a0']
bend_U = bend_cell.put(pin_U_pre)
wg_U = self.__strt_with_taper__(length=pitch/2+D_port,
width2=self.width,width1=bend_U.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_U.pin['b0'])
bend_U2 = bend_cell.put(wg_U.pin['b0'])
wg_U = self.__strt_with_taper__(length=self.Lmin+pitch/2,
width2=self.width,width1=bend_U2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_U2.pin['b0'])
pin_U_pre = wg_U.pin['b0']
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=pitch/2+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D.pin['b0'])
bend_D2 = bend_cell.put(wg_D.pin['b0'])
wg_D = self.__strt_with_taper__(length=self.Lmin+pitch/2,
width2=self.width,width1=bend_D2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D2.pin['b0'])
pin_D_pre = wg_D.pin['b0']
L = self.Lmin*3+pitch+L_bend
_cycle_ = 1
for _cycle_ in range(1,self.cycles-1):
bend_U = bend_cell.put(pin_U_pre)
wg_U = self.__strt_with_taper__(length=_cycle_*pitch+pitch/2+D_port,
width2=self.width,width1=bend_U.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_U.pin['b0'])
bend_U2 = bend_cell.put(wg_U.pin['b0'])
wg_U = self.__strt_with_taper__(length=self.Lmin+_cycle_*pitch+pitch/2,
width2=self.width,width1=bend_U2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_U2.pin['b0'])
pin_U_pre = wg_U.pin['b0']
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=_cycle_*pitch+pitch/2+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D.pin['b0'])
bend_D2 = bend_cell.put(wg_D.pin['b0'])
wg_D = self.__strt_with_taper__(length=self.Lmin+_cycle_*pitch+pitch/2,
width2=self.width,width1=bend_D2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D2.pin['b0'])
pin_D_pre = wg_D.pin['b0']
L = L+(_cycle_*pitch-pitch/2+D_port+self.Lmin+_cycle_*pitch+pitch/2)*2+L_bend*4
""" 2023.03.19 REVISED, the spiral will end at the same Y level with begining """
bend_D = bend_cell.put(pin_D_pre)
## adding bend connection to outside
if(self.port_angle==90 or self.port_angle==270 or self.port_angle==-90):
wg_D = self.__strt_with_taper__(length=(_cycle_+1)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D.pin['b0'])
pin_D_pre = wg_D.pin['b0']
elif(self.port_angle==180) :
wg_D = self.__strt_with_taper__(length=(_cycle_+1)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D.pin['b0'])
bend_D2 = bend_cell.put(wg_D.pin['b0'],flip=1)
pin_D_pre = bend_D2.pin['b0']
elif(self.port_angle==0 or self.port_angle==360) :
wg_D = self.__strt_with_taper__(length=(_cycle_+1.5)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp_port).put(bend_D.pin['b0'])
bend_D2 = bend_cell.put(wg_D.pin['b0'],flip=0)
pin_D_pre = bend_D2.pin['b0']
if (self.rib2strip):
taper = taper_xs2xs(xs_1=self.xs,xs_2='strip',w_1=self.w_bend_port,w_2=self.w_bend_port,L_taper=10,L_port=bend_sz[0]).cell.put(pin_D_pre)
pin_D_pre = taper.pin['b0']
taper = taper_xs2xs(xs_1=self.xs,xs_2='strip',w_1=self.w_bend_port,w_2=self.w_bend_port,L_taper=10,L_port=bend_sz[0]).cell.put(pin_U_pre)
pin_U_pre = taper.pin['b0']
""" 2023.03.19 REVISED, the begining will not be influenced by the rotation angle """
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()
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()
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()
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()
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)
self.L = L
## revise 2022.08.18
if (show_pins):
nd.put_stub()
return C
class spiral_rectangle:
"""
spiral rectangle primitive component.
This component builds the spiral rectangle layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
Rmax_bend : float, optional
Radius parameter in microns. Default is 10.
Rmin_bend : float, optional
Radius parameter in microns. Default is 10.
wmin_bend : float, optional
Value for the wmin_bend parameter. Default is 10.
Lmin : float, optional
Length parameter in microns. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is None.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
w_bend_port : Optional[float], optional
Width parameter in microns. Default is None.
Lport : int, optional
Length parameter in microns. Default is 10.
Ltp : int, optional
Length parameter in microns. Default is 10.
res : float, optional
Value for the res parameter. Default is 0.5.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
in_out_align : bool, optional
Value for the in_out_align parameter. Default is True.
Lpatch : float, optional
Length parameter in microns. Default is 0.05.
"""
def __init__(self,
name: str = None,
Dmin: float = 50,
Rmax_bend: float = 10,
Rmin_bend: float = 10,
wmin_bend: float = 10,
Lmin: float = 50,
width: float = 2,
w_port: float = None, ## not used at this moment
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
w_bend_port: Optional[float]=None,
Lport: int = 10,
Ltp: int = 10,
# Tres: int = 256,## resolution for one cycle, these two parameters aborted in 2023.1.4
# Bres: int = 64, ## resolution for bends, these two parameters aborted in 2023.1.4
res : float = 0.5, ## added in 2023.1.4, the length resolution
cell_xs_transition: Any=None,
port_angle: float = 180,
show_pins: bool = False,
sharp_patch:bool = True,
in_out_align: bool = True,
Lpatch: float = 0.05,
) -> None:
"""_summary_
Args:
name (str, optional): Name of the internal cell. Defaults to None.
shape (str, optional): circular or rectangular. Defaults to 'circle'.
Dmin (float, optional): Mimimum internal distance. Defaults to 50.
R_bend (float, optional): Radius of the bends. Defaults to 10.
Rmin_euler (float, optional): _description_. Defaults to 10.
Lmin (float, optional): Minimum length of the inner cycle. Defaults to 50.
width (float, optional): _description_. Defaults to 2.
w_port (float, optional): _description_. Defaults to 0.45.
w_bend_center (float, optional): _description_. Defaults to 1.
Rmin_bend_center (float, optional): _description_. Defaults to 10.
gap (float, optional): _description_. Defaults to 1.
cycles (float, optional): _description_. Defaults to 20.
xs (str, optional): _description_. Defaults to 'strip'.
layer (str, optional): _description_. Defaults to None.
Tres (int, optional): _description_. Defaults to 256.
port_angle (float, optional): _description_. Defaults to 90.
Euler_bend (bool, optional): _description_. Defaults to 'Euler'.
show_pins (bool, optional): _description_. Defaults to True.
sharp_patch (bool, optional): _description_. Defaults to True.
"""
self.Dmin = Dmin
self.Lmin = Lmin
self.Rmax_bend = Rmax_bend
self.Rmin_bend = Rmin_bend
self.wmin_bend = wmin_bend
self.cycles = cycles
self.width = width
self.w_port = w_port
self.gap = gap
self.xs = xs
self.layer = layer
self.Ltp = Ltp
self.Lpatch = Lpatch
self.name=name
if (self.name==None):
self.instantiate = False
else :
self.instantiate = True
self.port_angle=port_angle
self.sharp_patch= sharp_patch
self.w_bend_port = w_bend_port
self.Lport = Lport
if (hasattr(cell_xs_transition,'cell')):
self.cell_xs_transition = cell_xs_transition.cell
elif (isinstance(cell_xs_transition,nd.Cell)):
self.cell_xs_transition = cell_xs_transition
else :
self.cell_xs_transition = None
self.res = res
self.in_out_align = in_out_align
self.cell = self.generate_gds(show_pins=show_pins)
def __strt_with_taper__(self,width1,width2,xs,length,Ltp=15,Lstart=2):
with nd.Cell(instantiate=False) as C:
L_mm = length-Ltp*2-Lstart*2
if (L_mm>0):
instr_a1 = nd.strt(length=Lstart,width=width1,xs=xs).put(0,0,0)
nd.taper(length=Ltp,width1=width1,width2=width2,xs=xs).put()
nd.strt(length=L_mm,width=width2,xs=xs).put()
nd.taper(length=Ltp,width1=width2,width2=width1,xs=xs).put()
instr_b1 = nd.strt(length=Lstart,width=width1,xs=xs).put()
else :
instr_a1 = nd.strt(length=length/2,width=width1,xs=xs).put(0,0,0)
instr_b1 = nd.strt(length=length/2,width=width1,xs=xs).put()
nd.Pin(name='a0',pin=instr_a1.pin['a0']).put()
nd.Pin(name='b0',pin=instr_b1.pin['b0']).put()
return C
def generate_gds(self,show_pins):
if (self.w_port==None):
self.w_port = self.width
if (self.w_bend_port==None):
self.w_bend_port = self.width
""" Rectangluar Spiral """
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
pitch = (self.width+self.gap)*2 ## a bi-twsited circle
bend_rt = Clothoid(xs=self.xs,R=[self.Rmax_bend,self.Rmin_bend,self.Rmax_bend],
w=[self.w_bend_port,self.wmin_bend,self.w_bend_port],
A=[0,45,90],
dL_wg=self.res,
end_patch=False,
sharp_patch=self.sharp_patch)
bend_rt_anti = Clothoid(xs=self.xs,R=[self.Rmax_bend,self.Rmin_bend,self.Rmax_bend],
w=[self.w_bend_port,self.wmin_bend,self.w_bend_port],
A=[0,-45,-90],
dL_wg=self.res,
end_patch=False,
sharp_patch=self.sharp_patch)
""" Adding small patch to the bending connection """
with nd.Cell(instantiate=False) as bend_cell:
inst = bend_rt.cell.put(0,0,0)
nd.strt(xs=self.xs,width=self.w_bend_port,length=self.Lpatch).put(inst.pin['a0'].move(-self.Lpatch/2,0,0),flip=1)
nd.strt(xs=self.xs,width=self.w_bend_port,length=self.Lpatch).put(inst.pin['b0'].move(-self.Lpatch/2,0,0))
inst.raise_pins()
with nd.Cell(instantiate=False) as bend_cell_anti:
inst = bend_rt_anti.cell.put(0,0,0)
nd.strt(xs=self.xs,width=self.w_bend_port,length=self.Lpatch).put(inst.pin['a0'].move(-self.Lpatch/2,0,0),flip=1)
nd.strt(xs=self.xs,width=self.w_bend_port,length=self.Lpatch).put(inst.pin['b0'].move(-self.Lpatch/2,0,0))
inst.raise_pins()
# bend_cell = bend_rt.cell
# bend_cell_anti = bend_rt_anti.cell
bend_sz = bend_rt.sz
L_bend = bend_rt.L0
self.bend_cell = bend_cell
if (self.Dmin < bend_sz[1]*2):
self.Dmin = bend_sz[1]*2
print("WARNING: In <mxpic::passive::spiral>, Dmin too small")
D_port = self.Dmin - bend_sz[1]*2
with nd.Cell(instantiate=True,name="wg_mid_cell"+self.name) as wg_mid_cell:
wg = self.__strt_with_taper__(length=self.Lmin-bend_sz[0]*2-bend_sz[0],width2=self.width,width1=bend_cell.pin['a0'].
width,xs=self.xs,Ltp=self.Ltp).put(-self.Lmin/2+bend_sz[0]*2+bend_sz[0],0,0,flip=1)
bend_cell_anti.put(wg.pin['a0'],flip=0)
self.__strt_with_taper__(length=D_port,width2=self.width,width1=bend_cell.pin['a0'].width,xs=self.xs,Ltp=self.Ltp).put()
# bd = bend_cell.put(flip=0)
bd = bend_cell.put()
bd = self.__strt_with_taper__(length=bend_sz[0],
width2=bend_cell.pin['a0'].width,
width1=bend_cell.pin['a0'].width,xs=self.xs,Ltp=self.Ltp).put()
nd.Pin(name='a0',pin=bd.pin['b0']).put()
nd.Pin(name='b0',pin=wg.pin['b0']).put()
wg_mid = wg_mid_cell.put(-self.Lmin/2,self.Dmin/2,0)
L = self.Lmin-bend_sz[0]*2 + D_port + L_bend*2
pin_U_pre = wg_mid.pin['b0']
pin_D_pre = wg_mid.pin['a0']
bend_U = bend_cell_anti.put(pin_U_pre,flip=1)
wg_U = self.__strt_with_taper__(length=pitch/2+D_port,
width2=self.width,width1=bend_U.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_U.pin['b0'],flip=1)
L = L + pitch/2+D_port + L_bend
bend_U2 = bend_cell_anti.put(wg_U.pin['b0'],flip=1)
wg_U = self.__strt_with_taper__(length=self.Lmin+pitch/2,
width2=self.width,width1=bend_U2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_U2.pin['b0'],flip=1)
pin_U_pre = wg_U.pin['b0']
L = L + self.Lmin+pitch/2 + L_bend
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=pitch/2+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D.pin['b0'])
L = L + pitch/2+D_port + L_bend
bend_D2 = bend_cell.put(wg_D.pin['b0'])
wg_D = self.__strt_with_taper__(length=self.Lmin+pitch/2,
width2=self.width,width1=bend_D2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D2.pin['b0'])
pin_D_pre = wg_D.pin['b0']
L = L + self.Lmin+pitch/2 + L_bend
# L = self.Lmin*3+pitch+L_bend
_cycle_ = 1
for _cycle_ in range(1,self.cycles-1):
bend_U = bend_cell_anti.put(pin_U_pre,flip=1)
wg_U = self.__strt_with_taper__(length=_cycle_*pitch+pitch/2+D_port,
width2=self.width,width1=bend_U.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_U.pin['b0'],flip=1)
L = L+_cycle_*pitch+pitch/2+D_port+L_bend
bend_U2 = bend_cell_anti.put(wg_U.pin['b0'],flip=1)
wg_U = self.__strt_with_taper__(length=self.Lmin+_cycle_*pitch+pitch/2,
width2=self.width,width1=bend_U2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_U2.pin['b0'],flip=1)
pin_U_pre = wg_U.pin['b0']
L = L+self.Lmin+_cycle_*pitch+pitch/2+D_port+L_bend
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=_cycle_*pitch+pitch/2+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D.pin['b0'])
L = L+_cycle_*pitch+pitch/2+D_port+L_bend
bend_D2 = bend_cell.put(wg_D.pin['b0'])
wg_D = self.__strt_with_taper__(length=self.Lmin+_cycle_*pitch+pitch/2,
width2=self.width,width1=bend_D2.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D2.pin['b0'])
pin_D_pre = wg_D.pin['b0']
L = L+self.Lmin+_cycle_*pitch+pitch/2+L_bend
""" 2023.03.19 REVISED, the spiral will end at the same Y level with begining """
## adding bend connection to outside
if(self.port_angle==90 or self.port_angle==270 or self.port_angle==-90):
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=(_cycle_+1)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D.pin['b0'])
pin_D_pre = wg_D.pin['b0']
L = L+(_cycle_+1)*pitch+D_port+L_bend
elif(self.port_angle==180 and self.in_out_align) :
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=(_cycle_+1)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D.pin['b0'])
bend_D2 = bend_cell_anti.put(wg_D.pin['b0'])
pin_D_pre = bend_D2.pin['b0']
L = L+(_cycle_+1)*pitch+D_port+L_bend*2
elif(self.port_angle==180 and self.in_out_align==False):
pass
elif(self.port_angle==0 or self.port_angle==360) :
bend_D = bend_cell.put(pin_D_pre)
wg_D = self.__strt_with_taper__(length=(_cycle_+1.5)*pitch+D_port,
width2=self.width,width1=bend_D.pin['b0'].width,xs=self.xs,Ltp=self.Ltp).put(bend_D.pin['b0'])
bend_D2 = bend_cell.put(wg_D.pin['b0'],flip=0)
pin_D_pre = bend_D2.pin['b0']
L = L+(_cycle_+1.5)*pitch+D_port+L_bend*2
""" 2023.03.19 REVISED, the begining will not be influenced by the rotation angle """
""" 2023.09.18 REVISED, the xsection output can be defined with the transition area """
if (self.w_port !=self.width) :
pin_D_pre = nd.taper(length=self.Lport,width1=pin_D_pre.width,width2=self.w_port,xs=self.xs).put(pin_D_pre)
pin_U_pre = nd.taper(length=self.Lport,width1=pin_U_pre.width,width2=self.w_port,xs=self.xs).put(pin_U_pre)
""" 2023.09.18 REVISED, the transition area are only added at w_port area """
### Because putting transisiton in multimode area are dengerous
if (self.cell_xs_transition != None):
taper = self.cell_xs_transition.put(pin_D_pre)
pin_D_pre = taper.pin['b0']
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)
self.L = L
## revise 2022.08.18
if (show_pins):
nd.put_stub()
return C
class Spiral_Rect_STD(spiral_rectangle):
"""
Spiral Rect STD primitive component.
This component builds the Spiral Rect STD layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
R_bend : float, optional
Radius parameter in microns. Default is 10.
Lmin : float, optional
Length parameter in microns. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is 0.45.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
Lport : int, optional
Length parameter in microns. Default is 10.
in_out_align : bool, optional
Value for the in_out_align parameter. Default is True.
res : float, optional
Value for the res parameter. Default is 0.5.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
"""
def __init__(self,
name: str = None,
Dmin: float = 50,
R_bend: float = 10,
Lmin: float = 50,
width: float = 2,
w_port: float = 0.45,
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
Lport: int=10,
in_out_align: bool = True,
res: float = 0.5,
cell_xs_transition: Any=None,
port_angle: float = 180,
show_pins: bool = False,
sharp_patch: bool = True) -> None:
super().__init__(name=name,
Dmin=Dmin,
Rmax_bend=R_bend,
Rmin_bend=R_bend,
wmin_bend=width,
Lmin=Lmin,
width=width,
w_port=w_port,
gap=gap,
cycles=cycles,
xs=xs,
layer=layer,
w_bend_port=None,
Lport=Lport,
res=res,
cell_xs_transition=cell_xs_transition,
port_angle=port_angle,
show_pins=show_pins,
sharp_patch=sharp_patch,
in_out_align=in_out_align)
class spiral_circle:
"""
spiral circle primitive component.
This component builds the spiral circle layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is 0.45.
w_bend_center : float, optional
Width parameter in microns. Default is 1.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
Lport : int, optional
Length parameter in microns. Default is 10.
res : float, optional
Value for the res parameter. Default is 0.5.
rib2strip : bool, optional
Value for the rib2strip parameter. Default is True.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
Euler_Sbend : bool, optional
Value for the Euler_Sbend parameter. Default is False.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
strict_condition : bool, optional
Value for the strict_condition parameter. Default is False.
R_ratio_mamnual : Any, optional
Radius parameter in microns. Default is None.
"""
def __init__(self,
name: str = None,
Dmin: float = 50,
width: float = 2,
w_port: float = 0.45, ## not used at this moment
w_bend_center: float = 1,
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
Lport: int = 10,
res : float = 0.5, ## added in 2023.1.4, the length resolution
rib2strip: bool=True,
port_angle: float = 180,
Euler_Sbend: bool = False,
show_pins: bool = False,
sharp_patch:bool = True,
strict_condition: bool = False,
R_ratio_mamnual: Any = None,
) -> None:
"""_summary_
Args:
name (str, optional): Name of the internal cell. Defaults to None.
Dmin (float, optional): Mimimum internal distance. Defaults to 50.
width (float, optional): _description_. Defaults to 2.
w_port (float, optional): _description_. Defaults to 0.45.
w_bend_center (float, optional): _description_. Defaults to 1.
gap (float, optional): _description_. Defaults to 1.
cycles (float, optional): _description_. Defaults to 20.
xs (str, optional): _description_. Defaults to 'strip'.
layer (str, optional): _description_. Defaults to None.
Tres (int, optional): _description_. Defaults to 256.
port_angle (float, optional): _description_. Defaults to 90.
Euler_bend (bool, optional): _description_. Defaults to 'Euler'.
show_pins (bool, optional): _description_. Defaults to True.
sharp_patch (bool, optional): _description_. Defaults to True.
"""
self.Dmin = Dmin
self.cycles = cycles
self.width = width
self.w_port = w_port
self.gap = gap
self.xs = xs
self.layer = layer
self.name=name
if (self.name==None):
self.instantiate = False
else :
self.instantiate = True
self.port_angle=port_angle
self.w_bend_center= w_bend_center
self.Euler_Sbend= Euler_Sbend
self.sharp_patch= sharp_patch
self.Lport = Lport
self.rib2strip = rib2strip
self.res = res
self.strict_condition = strict_condition
self.R_ratio_mamnual = R_ratio_mamnual
self.cell = self.generate_gds(show_pins=show_pins)
""" Optimizing the bend radius for the minimum and central """
def opt_euler(self,R,R0):
(R1,R2) = R
R1 = R1
R2 = R2
[A,LA] = _my_poly_spiral(r=[R0/R1,R0/R2],theta=[0,90],res=0.01,R_max=1000,order=1)
[B,LA] = _my_poly_spiral(r=[R0/R2,R0],theta=[90,180],res=0.01,R_max=1000,order=1)
x_final = A[-1,0]+B[-1,0]
y_final = A[-1,1]+B[-1,1]
D_final = np.sqrt(x_final**2 + y_final**2)
A_final = abs(np.arctan(x_final/y_final))*180/pi
# Dmis = abs(D_final-D0)
# Amis = abs(abs(A_final)-abs(A0))
return [D_final,A_final]
def generate_gds(self,show_pins):
if (self.w_port==None):
self.w_port = self.width
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
if (self.layer==None):
pitch = (self.width+self.gap)*2 ## a bi-twsited circle
Dmin = self.Dmin
R0 = Dmin/2
kR = pitch/(np.pi*2)
K_att = (np.power(R0,2)+2*np.power(kR,2))/np.power((np.power(R0,2)+np.power(kR,2)),1.5)
R_att = 1/K_att
Atilt_con = abs(np.arctan(kR/R0))*180/pi ## the initial tilt norm of the conchoid
""" Calculating the spiral with internal Sbend """
if (self.Euler_Sbend):
if (self.R_ratio_mamnual==None):
n_swp = 201
R1_range = np.linspace(0.9,1.4,n_swp)
R2_range = np.linspace(2.4,2.6,n_swp)
mis = np.zeros((n_swp,n_swp))
for ix in range(0,len(R1_range)):
for iy in range(0,len(R2_range)):
temp = self.opt_euler((R1_range[ix],R2_range[iy]),R0=R_att)
mis[ix,iy] = abs(temp[0]-R0)+abs(temp[1]-abs(Atilt_con))*10
idx = mis.argmin()
ix = idx//n_swp
iy = np.mod(idx,n_swp)
Rc_ratio = R1_range[ix]
Rm_ratio = R2_range[iy]
final_mismatch = self.opt_euler((Rc_ratio,Rm_ratio),R_att)
print("====================================================")
print("Optimized D/A = %.3f -- %.3f" % (final_mismatch[0],final_mismatch[1]))
print("Target D/A = %.3f -- %.3f" % (R0,Atilt_con))
print("Optimized para = %.3f -- %.3f" % (Rc_ratio,Rm_ratio))
else :
Rc_ratio = self.R_ratio_mamnual[0]
Rm_ratio = self.R_ratio_mamnual[1]
print("====================================================")
print("manual para = %.3f -- %.3f" % (Rc_ratio,Rm_ratio))
for layers,growx,growy,acc in nd.layeriter(xs=self.xs):
(a1,b1), (a2,b2),c1,c2 = growx
""" Generating Central Euler bend """
if (self.Euler_Sbend == True):
spr_bend = Clothoid(xs=self.xs,R=[R_att/Rc_ratio,R_att/Rm_ratio,R_att],
w=[self.w_bend_center,self.width],A=[0,90,180],dL_wg=self.res,
width_type='dual_sine',dL_cal=0.01)
else :
""" Genreating Circular bend for center """
spr_bend = Clothoid(xs=self.xs,R=[R0/2,R0/2,R0/2],
w=[self.width,self.width],A=[0,90,180],dL_wg=self.res,
width_type='dual_sine',dL_cal=0.01)
w_cur = self.width*(a1-a2)+(b1-b2)
if (w_cur<pitch or self.sharp_patch==False):
if (self.R_ratio_mamnual==None):
Atilt = np.arctan(spr_bend.vtx_center[-1,0]/spr_bend.vtx_center[-1,1])*180/pi
else:
if (self.R_ratio_mamnual[2]==None):
Atilt = np.arctan(spr_bend.vtx_center[-1,0]/spr_bend.vtx_center[-1,1])*180/pi
else :
Atilt = self.R_ratio_mamnual[2]
self.Atilt = Atilt
D0 = np.sqrt(abs(spr_bend.vtx_center[-1,0])**2 + abs(spr_bend.vtx_center[-1,1])**2)
Arot = self.cycles*180
IN_L = spr_bend.cell.put('a0',0,0,-90-Atilt + Arot,flip=1)
IN_R = spr_bend.cell.put('a0',0,0, 90-Atilt + Arot,flip=1)
# R_act = spr_bend.sz[1]*np.cos(Atilt/180*np.pi)
# R_act = spr_bend.sz[1]
R_act = np.sqrt(np.abs(IN_L.pin['b0'].x**2 + IN_L.pin['b0'].y**2))
if (self.strict_condition==False):
kR = np.tan(Atilt_con/180*np.pi)*R_act
pitch_actual = kR*2*np.pi
gap_actual = (pitch_actual - self.width*2)/2
print("Actual Clothoid gap: %.3f" % (gap_actual))
""" Standard part """
SPR_U = Conchoid(R0=R_act,kR=kR,T=self.cycles*pi,w=self.width*(a1-a2)+(b1-b2),w_end=self.w_port,
layer=layers,
final_flat=180*self.cycles,
begin_flat=self.Atilt,
res=self.res)
if (self.Euler_Sbend):
print("Actual D/A = %.3f -- %.3f" % (D0,self.Atilt))
print("Actual D/A Clothoid %.3f -- %.3f" % (R_act,SPR_U.Atilt))
print("")
SPR_U_INST = SPR_U.cell.put('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
nd.taper(layer=layers,width1=w_cur,width2=w_cur-0.01,length=0.01).put(IN_L.pin['b0'].x,IN_L.pin['b0'].y,-90-self.Atilt+Arot)
nd.taper(layer=layers,width1=w_cur,width2=w_cur-0.01,length=0.01).put(IN_L.pin['b0'].x,IN_L.pin['b0'].y, 90-self.Atilt+Arot)
""" 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=180*self.cycles+180-self.port_angle,w_end=self.w_port,
begin_flat=self.Atilt,
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)
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)
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
nd.strt(length=sz,width=sz,layer=layers).put(-sz/2,0,0)
self.L = SPR_U.L+SPR_D.L
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()
if show_pins:
nd.put_stub()
return C
class Spiral_Cicle_MM(spiral_circle):
"""
Spiral Cicle MM primitive component.
This component builds the Spiral Cicle MM layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is 0.45.
w_bend_center : float, optional
Width parameter in microns. Default is 1.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
Lport : int, optional
Length parameter in microns. Default is 10.
res : float, optional
Value for the res parameter. Default is 0.5.
rib2strip : bool, optional
Value for the rib2strip parameter. Default is True.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
strict_condition : bool, optional
Value for the strict_condition parameter. Default is False.
"""
def __init__(self,
name: str = None,
Dmin: float = 50,
width: float = 2,
w_port: float = 0.45,
w_bend_center: float = 1,
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
Lport: int=10,
res: float = 0.5,
rib2strip: bool=True,
port_angle: float = 180,
show_pins: bool = False,
sharp_patch: bool = True,
strict_condition: bool=False) -> None:
super().__init__(name,
Dmin,
width,
w_port,
w_bend_center,
gap, cycles,
xs, layer,
Lport, res,
rib2strip, port_angle,
Euler_Sbend=True,
show_pins=show_pins,
sharp_patch=sharp_patch,
strict_condition=strict_condition)
class Spiral_Cicle_STD(spiral_circle):
"""
Spiral Cicle STD primitive component.
This component builds the Spiral Cicle STD layout cell.
Parameters
----------
name : str, optional
Unique identifier for the device cell. Default is None.
Dmin : float, optional
Value for the Dmin parameter. Default is 50.
width : float, optional
Width parameter in microns. Default is 2.
w_port : float, optional
Width parameter in microns. Default is 0.45.
gap : float, optional
Spacing or gap parameter in microns. Default is 1.
cycles : float, optional
Count or repetition parameter. Default is 20.
xs : str, optional
Layer or cross-section name used by the device. Default is 'strip'.
layer : str, optional
Layer or cross-section name used by the device. Default is None.
Lport : int, optional
Length parameter in microns. Default is 10.
res : float, optional
Value for the res parameter. Default is 0.5.
rib2strip : bool, optional
Value for the rib2strip parameter. Default is True.
port_angle : float, optional
Value for the port_angle parameter. Default is 180.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
sharp_patch : bool, optional
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
strict_condition : bool, optional
Value for the strict_condition parameter. Default is False.
"""
def __init__(self,
name: str = None,
Dmin: float = 50,
width: float = 2,
w_port: float = 0.45,
gap: float = 1,
cycles: float = 20,
xs: str = 'strip',
layer: str = None,
Lport: int=10,
res: float = 0.5,
rib2strip: bool=True,
port_angle: float = 180,
show_pins: bool = False,
sharp_patch: bool = True,
strict_condition: bool=False) -> None:
super().__init__(name,
Dmin,
width,
w_port,
w_bend_center=width,
gap=gap,
cycles=cycles,
xs=xs,
layer=layer,
Lport=Lport,
res=res,
rib2strip=rib2strip,
port_angle=port_angle,
Euler_Sbend=False,
show_pins=show_pins,
sharp_patch=sharp_patch,
strict_condition=strict_condition)